suppressPackageStartupMessages({

library(ArchR)
library(parallel)
library(tidyverse)
library(SingleCellExperiment)
library(zellkonverter)
library(dtwclust)
})
### VARIABLES

proj_name <- "/omics/groups/OE0533/internal/katharina/scDoRI/gastrulation_data_new/Kathi/07_gene_acitivity_scores/"
p2g_links_file <- "/omics/groups/OE0533/internal/katharina/scDoRI/gastrulation_data_new/Kathi/p2g_links"

# location of seurat file
seurat_file <- "/omics/groups/OE0533/internal/katharina/scDoRI/gastrulation_data_new/Kathi/rna_seurat"

seacell_csv_file <- "/omics/groups/OE0533/internal/katharina/scDoRI/gastrulation_data_new/Kathi/perturbation_sea_df_new"
# which GeneScoreMatrix to use, needs to be in getAvailableMatrices(proj)
GeneScoreMatrix <- "GeneScoreMatrix_geneBody"
proj <- loadArchRProject(proj_name, showLogo = FALSE)
## Successfully loaded ArchRProject!
p2g <- getPeak2GeneLinks(
  ArchRProj = proj,
  corCutOff = -1,
  resolution = 1,
  FDRCutOff = 1e-04,
  varCutOffATAC = .25,
  varCutOffRNA = .25, 
  returnLoops = FALSE
)
peaks <- getMatrixFromProject(proj, useMatrix = "PeakMatrix", binarize = FALSE)
## ArchR logging to : ArchRLogs/ArchR-getMatrixFromProject-26246c6d1fb9-Date-2022-05-27_Time-10-30-20.log
## If there is an issue, please report to github with logFile!
## 2022-05-27 10:42:18 : Organizing colData, 11.967 mins elapsed.
## 2022-05-27 10:42:19 : Organizing rowData, 11.975 mins elapsed.
## 2022-05-27 10:42:19 : Organizing rowRanges, 11.975 mins elapsed.
## 2022-05-27 10:42:19 : Organizing Assays (1 of 1), 11.976 mins elapsed.
## 2022-05-27 10:44:05 : Constructing SummarizedExperiment, 13.744 mins elapsed.
## 2022-05-27 10:44:07 : Finished Matrix Creation, 13.778 mins elapsed.
PEAK_MAT <- assays(peaks)[[1]]

# read in gne expresssion matrix
gene_expr <- getMatrixFromProject(proj, 
                                  useMatrix = "GeneExpressionMatrix")
## ArchR logging to : ArchRLogs/ArchR-getMatrixFromProject-262480c8aab-Date-2022-05-27_Time-10-44-07.log
## If there is an issue, please report to github with logFile!
## 2022-05-27 10:48:06 : Organizing colData, 3.976 mins elapsed.
## 2022-05-27 10:48:06 : Organizing rowData, 3.984 mins elapsed.
## 2022-05-27 10:48:06 : Organizing rowRanges, 3.984 mins elapsed.
## 2022-05-27 10:48:06 : Organizing Assays (1 of 1), 3.984 mins elapsed.
## 2022-05-27 10:48:38 : Constructing SummarizedExperiment, 4.51 mins elapsed.
## 2022-05-27 10:48:40 : Finished Matrix Creation, 4.546 mins elapsed.
EXPR_MAT <- assays(gene_expr)[[1]]
rownames(EXPR_MAT) <- rowData(gene_expr)$name

# read in archr gene activity scores
archr_scores <- getMatrixFromProject(proj, useMatrix = "GeneScoreMatrix_geneBody")
## ArchR logging to : ArchRLogs/ArchR-getMatrixFromProject-26247ac8f0ac-Date-2022-05-27_Time-10-48-40.log
## If there is an issue, please report to github with logFile!
## 2022-05-27 10:57:49 : Organizing colData, 9.159 mins elapsed.
## 2022-05-27 10:57:50 : Organizing rowData, 9.167 mins elapsed.
## 2022-05-27 10:57:50 : Organizing rowRanges, 9.167 mins elapsed.
## 2022-05-27 10:57:50 : Organizing Assays (1 of 1), 9.167 mins elapsed.
## 2022-05-27 10:59:41 : Constructing SummarizedExperiment, 11.017 mins elapsed.
## 2022-05-27 10:59:43 : Finished Matrix Creation, 11.05 mins elapsed.
# cp_names <- colnames(colData(archr_scores))
# cp_names[20] <- "celltypes"
# colnames(colData(archr_scores)) <- cp_names

archr_scores_mat <- assays(archr_scores)[[1]]
rownames(archr_scores_mat) <- rowData(archr_scores)$name


hvg_list <- readRDS("Kathi/hvg.rds")


meta_rna <- rowData(gene_expr) %>% as.data.frame() %>% mutate(row_index = seq(nrow(.)))
idx <- (meta_rna %>% filter(name %in% hvg_list))$row_index

expr_sub <- EXPR_MAT[idx, ]


seacells <- read.csv(seacell_csv_file)



links <- p2g %>% as.data.frame() %>% 
  filter(Correlation > 0.2) %>% 
  filter(idxRNA %in% idx) 

stopifnot(all(links$Correlation > 0))


p2g_mat <- sparseMatrix(i = links$idxRNA,
             j = links$idxATAC,
             x= links$Correlation, 
             dims = c(dim(EXPR_MAT)[1],
             dim(PEAK_MAT)[1]))

rownames(p2g_mat) <- rowData(gene_expr)$name


rownames(PEAK_MAT) <- seq.int(dim(PEAK_MAT)[1])
colnames(p2g_mat) <- seq.int(dim(PEAK_MAT)[1])



# remove columns of peaks which are not linked to any peak
p2g_mat_sub <- p2g_mat[, colSums(p2g_mat) != 0]
# use only highly variable genes
p2g_mat_sub <- p2g_mat_sub[hvg_list, ]
# remove any genes which are not linked to any peak
p2g_mat_sub <- p2g_mat_sub[rowSums(p2g_mat_sub) != 0, ]
stopifnot(all(rownames(p2g_mat_sub) %in% hvg_list))
stopifnot(any(is.na(p2g_mat_sub) == FALSE))

# keep only peaks which are linked to genes in the accessibility matrix
peak_mat_sub <- PEAK_MAT[colnames(p2g_mat_sub), ]
stopifnot(rownames(peak_mat_sub) == colnames(p2g_mat_sub))
#stopifnot(any(is.na(peak_mat_sub) == FALSE))
stopifnot(dim(peak_mat_sub)[1] == dim(p2g_mat_sub)[2])

expr_mat_sub <- EXPR_MAT[as.vector(rownames(p2g_mat_sub)), ]
GENE_ANNO <- rowData(gene_expr)
gene_colData <- colData(gene_expr) %>% as.data.frame()
gene_colData <- dplyr::rename(gene_colData, celltypes = celltype.mapped)


archr_colData <- colData(archr_scores) %>% as.data.frame()
archr_colData <- dplyr::rename(archr_colData, celltypes = celltype.mapped )

#archr_scores_mat <- archr_scores_mat[, 1:1000]
archr_colData <- archr_colData %>% rownames_to_column("cell") %>%
  dplyr::filter(cell %in% colnames(archr_scores_mat)) %>%
  column_to_rownames("cell")

archr_scores_sub <- archr_scores_mat[as.vector(rownames(expr_mat_sub)), seacells$index]

Functions

Function to create aggregate matrices:

# the data matrix needs to be of dimension features x cells
# metadata of data matrix which contains celltypes
# needs to be called "celltypes"
create_celltype_aggregates <- function(metadata, data_matrix, celltypes) {
  #create empty matrix to store aggregates
  agg <- matrix(data = 0,
                nrow = nrow(data_matrix),
                ncol = length(celltypes),
                dimnames = list(rownames(data_matrix), celltypes))
  

  for (celltype in celltypes) {
    barcodes <- rownames(metadata %>%
                           as.data.frame() %>%
                           dplyr::filter(celltypes == celltype))
    if (length(barcodes) == 1){
        agg[, celltype] <- data_matrix[, barcodes]
        print(paste0("Warning! Celltype", celltype, "contains only one cell."))
    } else{
      agg[, celltype] <- rowSums(data_matrix[, barcodes])
    }
  }
  stopifnot(any(is.na(agg)) == FALSE)
  return(agg)
}


create_celltype_aggregates_p2g_scores <- function(gene_expr_metadata, p2g_score_matrix, celltypes) {
    #create empty matrix to store aggregates
  agg <- matrix(data = 0,
                nrow = nrow(p2g_score_matrix),
                ncol = length(celltypes),
                dimnames = list(rownames(p2g_score_matrix), celltypes))
  

  for (celltype in celltypes) {
    barcodes <- rownames(gene_expr_metadata %>%
                           as.data.frame() %>%
                           dplyr::filter(celltypes == celltype))
    if (length(barcodes) == 1) {
      agg[, celltypes] <- p2g_score_matrix[, barcodes]
      print(paste0("Warning! Celltype", celltype, "contains only one cell."))
    } else {
      agg[, celltype] <- rowSums(p2g_score_matrix[, barcodes])
    }
  }
  stopifnot(any(is.na(agg)) == FALSE)
  return(agg)
}


create_seacell_aggregates <- function(data_matrix, seacells_df){
  agg <- matrix(data = 0,
                nrow = nrow(data_matrix),
                ncol = length(unique(seacells_df$SEACell)),
                dimnames = list(rownames(data_matrix),
                              unique(seacells_df$SEACell)))
  #stopifnot(nrow(agg) == nrow(data_matrix))
  for (seacell in unique(seacells_df$SEACell)){
    #print(seacell)
    barcodes <- (seacells_df %>% dplyr::filter(SEACell == seacell))$index
    #print(barcodes)
    if (length(barcodes) == 1){
      agg[, seacell] <- data_matrix[, barcodes]
      print(paste0("Warning! SEACell", seacell, "contains only one cell."))
    } else{
      agg[, seacell] <- rowSums(data_matrix[, barcodes])
    }
  }
  stopifnot(any(is.na(agg)) == FALSE)
  return(agg)
}

Function to compute row-wise correlations between two matrices:

ROW_CORR_THEME <-   theme(axis.text.x = element_text(size = 12),
        axis.text.y = element_text(size = 12),
        axis.title.x = element_text(size = 15), # change size of axis title
        axis.title.y = element_text(size = 15),
        plot.title = element_text(hjust = 0.5, size = 20),
        legend.position = "None", 
        panel.grid.major = element_line(colour = "grey"),   # Major grid lines
        panel.background = element_rect(fill = "white", colour = "black"),
        aspect.ratio = 0.4)  





rowwise_correlations <- function(MatrixA, MatrixB, name) {
  intersect_genes <- intersect(rownames(MatrixA), rownames(MatrixB))
  MatrixA <- MatrixA[intersect_genes, ]
  MatrixB <- MatrixB[intersect_genes, ]
  correlations <- c()
  for (i in seq.int(dim(MatrixA)[1])) {
    rowA <- MatrixA[i, ]
    rowA <- rowA - mean(rowA)
    if (sd(rowA) != 0) {
      rowA <- rowA / sd(rowA)
    }
  
    rowB <- MatrixB[i, ]
    rowB <- rowB - mean(rowB)
    if (sd(rowB) != 0){
      rowB <- rowB / sd(rowB)
    }
    
    corr_value <- mean(rowA * rowB)
    correlations <- c(correlations, corr_value)
  }
  names(correlations) <- rownames(MatrixA)
  plot <- ggplot() + geom_histogram(aes(x = correlations), 
                                    bins = 200, 
                                    fill="#69b3a2") + labs(title = paste0(name)) +
    ROW_CORR_THEME
    
  return(list(correlations, plot))
}

Plot Themes

Plot Theme for comparing correlations.

CORR_THEME <-   theme(axis.text.x = element_text(size = 12),
        axis.text.y = element_text(size = 12),
        axis.title.x = element_text(size = 15), # change size of axis title
        axis.title.y = element_text(size = 15),
        plot.title = element_text(hjust = 0.5, size = 20),
        legend.position = "None", 
        panel.grid.major = element_line(colour = "grey"),   # Major grid lines
        panel.background = element_rect(fill = "white", colour = "black"),
        aspect.ratio = 1)  

Plot theme for plots which are mcuh wider than high.

THEME_LONG <-   theme(axis.text.x = element_text(size = 12),
        axis.text.y = element_text(size = 12),
        axis.title.x = element_text(size = 15), # change size of axis title
        axis.title.y = element_text(size = 15),
        plot.title = element_text(hjust = 0.5, size = 20),
        legend.position = "None", 
        panel.grid.major = element_line(colour = "grey"),   # Major grid lines
        panel.background = element_rect(fill = "white", colour = "black"),
        aspect.ratio = 0.2)

Plot theme for standard plots (slighly wider than high).

CUSTOM_THEME <-   theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1, size = 12),
        axis.text.y = element_text(size = 12),
        axis.title.x = element_text(size = 20), # change size of axis title
        axis.title.y = element_text(size = 20),
        plot.title = element_text(hjust = 0.5, size = 25),
        legend.position = "None", 
        panel.grid.major = element_line(colour = "grey"),   # Major grid lines
        panel.background = element_rect(fill = "white", colour = "black"),
        aspect.ratio = 0.3)

Celltype aggregates

ArchR gene activity scores

To compute the correlations between gene expression and ArchR gene activity scores I first aggregated cells according to celltypes to compute correlations. As can be seen in the plot below, this yields very high correlation values. This is as expected, since in (Granja JM 2021) the authors compared 52 different ways of computing gene activity scores from ATAC-seq data and found their method to be the best one.

name <- "ArchR_scores, Celltype aggregates"

archr_scores_agg <- create_celltype_aggregates(archr_colData, archr_scores_sub, 
                                              unique(archr_colData$celltypes))

expr_agg_celltypes <- create_celltype_aggregates(gene_colData, expr_mat_sub, 
                                                 unique(gene_colData$celltypes))

p2g_agg_celltypes <- create_celltype_aggregates_p2g_scores(gene_colData, p2g_scores,
                                                           unique(gene_colData$celltypes))

archr_corrs <- rowwise_correlations(expr_agg_celltypes, archr_scores_agg, "Correlation gene expr. & ArchR gene activity scores")
p2g_corrs <- rowwise_correlations(expr_agg_celltypes, p2g_agg_celltypes, "Correlation gene expr. & p2g activity scores")

cowplot::plot_grid(archr_corrs[[2]], p2g_corrs[[2]], ncol = 1)

ggsave("Kathi/plots/Correlations_cell_aggregates.pdf")
## Saving 10 x 6 in image
ggplot() + #geom_density2d_filled(aes(x = correlations_250kb, y = corrs[1])) #+
  geom_point(aes(y = archr_corrs[[1]], x = p2g_corrs[[1]])) +
  geom_density_2d_filled(aes(y = archr_corrs[[1]], x = p2g_corrs[[1]]), alpha = 0.5) +
  geom_line(aes(x =  archr_corrs[[1]],  archr_corrs[[1]]), color = "red") +
  labs(y = "Correlation gene expr. & p2g activity scores",
       x = "Correlation gene expr. & ArchR gene activity scores",
       title = "Celltype aggregates") +
  CORR_THEME

ggsave("Kathi/plots/comparing_archr_all_p2g_links.pdf")
## Saving 6 x 6 in image

SEACell aggregates

Instead of using celltype aggregates as above, another option is to use SEACells as described in (Persad et al. 2022). These were computed using Python and the resulting cell aggregates (“metacells”) are used for aggregating gene expression and gene activity scores below. The correlations when using SEACells are much higher than the correlations obtained using the ArchR cell aggregates. For this reason I will use SEACells for computing correlations in the following steps.

#seacells <- seacells %>% dplyr::filter(index %in% colnames(EXPR_MAT))

stopifnot(nrow(p2g_scores) == nrow(expr_mat_sub))

seacell_p2g_agg <- create_seacell_aggregates(p2g_scores, seacells)
seacell_rna_agg  <- create_seacell_aggregates(expr_mat_sub, seacells)
seacell_archr_agg <- create_seacell_aggregates(archr_scores_sub, seacells)


seacell_corr_p2g <- rowwise_correlations(seacell_rna_agg , seacell_p2g_agg, 
                                         "P2g links of entire chromosome, SEAcells" )

seacell_corr_archr <- rowwise_correlations(seacell_rna_agg, seacell_archr_agg, 
                                           "ArchR gene activity scores, SEAcells")

cowplot::plot_grid(seacell_corr_p2g[[2]] , seacell_corr_archr[[2]], ncol = 1)

ggplot() + #geom_density2d_filled(aes(x = correlations_250kb, y = corrs[1])) #+
  geom_point(aes(x = seacell_corr_p2g[[1]], y = seacell_corr_archr[[1]])) +
  geom_density_2d_filled(aes(x = seacell_corr_p2g[[1]], y = seacell_corr_archr[[1]]), alpha = 0.5) +
  geom_line(aes(x = seacell_corr_archr[[1]], y = seacell_corr_archr[[1]]), color = "red" )  +
  labs(x = "Correlation gene expr. & all p2g activity scores",
       y = "Correlation gene expr. & ArchR gene activity scores",
       title = "SEACells, all p2g links") +
  CORR_THEME +
  theme(legend.position = "None")

ggsave("Kathi/plots/seacell_aggreagates_p2g_archr.pdf")
## Saving 6 x 6 in image

Distance weights

Using ArchR (Granja JM 2021) I computed peak-to-gene links across the entire chromosome, but not between chromsomes. This means that a lot of correlations are found between peaks very far away from the promoter/gene they are linked to. Even though these correlations can be quite high and interactions between enhancers and promoters can occur over megabase distances, a real biological interaction becomes less likely the larger the distance is. Therefore, since wer are interested in biologically relevant and not spurious correlations. Therefore, as suggested by (Granja JM 2021), I added distance weights, such that farther away peaks linked to a gene contribute less to the gene activity score of this particular gene.

Here, I used a distance decay from the TSS, computed as follows:

\(weight = e^{-(abs(distTSS/c))}\) with \(c\) being a constant determining the exponential decay rate of the distance weights. Below I tried different rates to better understand whether we can improve the gene activity scores by giving a higher weight to close peaks than to far away peaks. As can be seen below this did not improve, the scores, but rather the scores became worse, which is probably due to the fact that most correlation values will get very small weights this way and most peaks linked with a gene, even if the correlation value is high, will not contribute to the gene activity score anymore.

**Careful: The p2g inks in ArchR are computed for peak and gene pairs which are within a certain distance from each other. However, not the real TSS of a gene is used for this, but rater the distance between start coordinate of a gene and peak start coordinate, not taking into consideration the strand directionality.

Gene window, no distance weights

There are two options when defining the gene window. One option is to extend +/- 100bp up- and downstream of the TSS. However, since genes have different sizes, some gene bodies might be much larger than these gene windows. The second option is to extend the gene window not from the TSS, but from the start and end corrdinate of the gene body respectively. This way, more peaks will be taken into consideration if a gene is larger, simply because the gene window will be larger. Therefore, in ArchR they use an additional weight for the gene body size to account for this effect. Here, we extend the gene window around the TSS. As can be seen in the plot below, this does not yield better results, probably, because we are removing a lot of correlations which are high and, therefore, important for the prediction.

This is not what would be expected, since some high correlations within the gene window are very likely to be biologically important and should recapitulate gene expression quite well. This is also shown by the ArchR gene activity scores, which use gene window as well to restric the influence of accessible regions to a certain window around the gene’s TSS. One reason could be that the peak-to-gene links identified by simple correlations are not biologically meaningful, therefore also very far away correlations are important for recapitulating gene expression.

Gene window around TSS

# As input for this function it is best to use only the most highly variable genes
compute_gene_window_score <- function(p2g_mat_sub, peak_mat, links, p2g_original, gene_anno){
  
  gene_anno_original <- gene_anno
  # create gene annotations with start coordinate of each gene
  # subset to contain only genes which are included in our peak2gene matrix
  gene_anno <- gene_anno %>% 
    as.data.frame() %>%
    mutate(idxRNA = seq(nrow(.))) %>% 
    dplyr::filter(name %in% rownames(p2g_mat_sub)) %>%
    mutate(strand = ifelse(strand == 1, "+", "-")) %>%
    mutate(start_coord = ifelse(strand == "+", start, end)) %>% 
    rename(gene = name) #%>% GRanges()

  # extend gene regions +/- 100bp up- and downstream of the TSS
  gene_regions  <- resize(gene_anno %>% GRanges(), width = 1)
  extendedGeneRegion <- (suppressWarnings(extendGR(gene_regions,
                                                         upstream = 100000,
                                                         downstream = 100000)))
  # subset atac granges & get middle of each peak
  pos_atac_granges <-  metadata(p2g_original)[[1]]  %>% 
    as.data.frame() %>%
    mutate(idxATAC = seq(nrow(.))) %>% 
    # group_by(seqnames) %>%
    # mutate(idx = seq_along(seqnames)) %>% 
    # ungroup %>%
    #tidyr::unite(chr_idx, seqnames, idx, remove = FALSE, sep = "_") %>% 
    dplyr::filter(idxATAC %in% colnames(p2g_mat_sub)) %>% 
    mutate(middle = start + 300) #%>% GRanges() 
  
  #TODO: Filter for genes!
  stopifnot(length(unique(links$idxATAC)) == dim(pos_atac_granges)[[1]])
  stopifnot(length(unique(links$idxRNA)) == dim(gene_anno)[[1]])
  #p2g_filt <- p2g_original %>% as.data.frame() %>% filter(gene %in% rownames(p2g_mat))
  
  
    # find overlapping peaks and gene window in chromosome-aware fashion
  tmp <- suppressWarnings(findOverlaps(extendedGeneRegion, pos_atac_granges %>% GRanges()))
  
  print(paste0("Out of ", subjectLength(tmp), " peaks only ",
               length(unique(subjectHits(tmp))), " peaks are found within gene window of 200kb."))
  
  
  ### some plots
  p1 <- (tmp %>% as.data.frame() %>% 
         group_by(queryHits) %>% # gene region
         summarize(n = n()) %>% # get number of peaks overlapping with a gene region
         ggplot() + geom_histogram(aes(x = n), bins = 100, fill="#69b3a2") +
         labs(title = "Gene window of size +/- 100kb from TSS",
             x = "#peaks within gene window")) +
    CORR_THEME
  
  
  
  # combine the three dataframes
  p2g_join <- left_join(links, as.data.frame(pos_atac_granges),
                        by = "idxATAC")
  p2g_join <- left_join(p2g_join, as.data.frame(gene_anno),
                        by = "idxRNA", suffix = c(".atac", ".rna"))

  # compute distance and distance weights 
  p2g_join <- p2g_join %>% 
    mutate(distance = abs(start_coord - middle))
  
  
  p2 <- p2g_join %>% ggplot() +
    geom_histogram(aes(x = distance), bins = 100, fill="#69b3a2") +
    labs(title = "P2g links within +/- 100kb window", x = "Distance (bp)") +
    geom_vline(xintercept  = 100000, color = "orange") +
    CORR_THEME

  
  # p2 <- p2g_join %>% ggplot() +
  #   geom_histogram(aes(x = (distance_weight)), bins = 100) +
  #   scale_y_log10() +
  #   labs(title = "Distance Weights", x = "distance weights") 

  print(cowplot::plot_grid(p1, p2, ncol = 2))#),  ncol = 2))
  
  
  ggsave("Kathi/plots/gene_window_distance.pdf")
  
    
  # create a dataframe of all peaks which overlap their corresponding gene window
  peaks_in_gene_window <- data.frame(gene = gene_regions[queryHits(tmp)]$gene, 
             peak = (pos_atac_granges %>% GRanges())[subjectHits(tmp)]$idxATAC) %>% 
    unite(peak_gene_window, gene, peak, sep = "#", remove = FALSE)
  
  # filter the p2g link dataframe for only peaks which are within a gene window
  corr_window <- p2g_join %>%
    unite(peak_gene_window, gene, idxATAC, sep = "#", remove = FALSE) %>%
    dplyr::filter(peak_gene_window %in% peaks_in_gene_window$peak_gene_window) 


  ### PLOTS
  
  p1 <- corr_window %>% 
    ggplot() +
    geom_histogram(aes(x = Correlation), bins = 200, fill = "#69b3a2") +
    labs(title = "P2g links within +/- 100kb gene window") +
    THEME_LONG
  
  p2 <- corr_window %>% 
    ggplot() +
    geom_histogram(aes(x = distance), bins = 200, fill = "#69b3a2") +
    labs(x = "Distance (bp)") +
    THEME_LONG
  
  p3 <- corr_window %>% 
    mutate(bin = cut_width(distance, width=10000, boundary=0)) %>% 
    ggplot() +
    geom_violin(aes(x = bin, y = Correlation), fill = "#69b3a2", alpha = .6, scale = "width") +
    geom_boxplot(aes(x = bin, y = Correlation), alpha = 0) +
    labs(title = "P2g links within +/- 100kb gene window",
         x = "Distance (10kp bins)") +
    scale_x_discrete(guide = guide_axis(angle = 45)) +
    THEME_LONG

  print(cowplot::plot_grid(p1, p2, ncol = 1))
  
  ggsave("Kathi/plots/distance_correlation.pdf")
  
  print(p3)
  ggsave("Kathi/plots/Distance_vs_corr_gene_window.pdf")
  
  # p1 <- ggplot() + 
  #   geom_histogram(aes(x = rowSums(p2g_mat_sub > 0)), bins = 200, fill = "#69b3a2") +
  #   scale_y_log10() +
  #   labs(title = "# peaks correlated with each gene", 
  #        x = "number of peaks", y = "log10(count)") 
  #   
  # 
  # p2 <- ggplot() + 
  #   geom_histogram(aes(x = colSums(p2g_mat_sub > 0)), bins = 70, fill = "#69b3a2") +
  #   scale_y_log10() +
  #   labs(title = "# genes correlated with each peak",
  #        y = "log10(count)", x = "number of genes")
  
  p3 <- ggplot() + 
    geom_histogram(aes(x = rowSums(p2g_mat_sub > 0)), bins = 200, fill = "#69b3a2") +
    labs(title = "# peaks correlated with each gene", 
         x = "number of peaks", y = "count") +
    CORR_THEME
    
  
  p4 <- ggplot() + 
    geom_histogram(aes(x = colSums(p2g_mat_sub > 0)), bins = 70, fill = "#69b3a2") +
    labs(title = "# genes correlated with each peak",
         y = "count", x = "number of genes") +
    CORR_THEME
  
  print(cowplot::plot_grid(p3, p4, ncol = 2))

  
  ggsave("Kathi/plots/genes_peaks_correlations.pdf")
  
  
 # Create a matrix of distance weight 
  p2g_links_gene_window <- Matrix::sparseMatrix(
      i = corr_window$idxRNA, 
      j = corr_window$idxATAC, 
      x = corr_window$Correlation, 
      dims = c(nrow(gene_anno_original), nrow(peak_mat)),
      dimnames = list(gene_anno_original$name,
                      seq.int(nrow(peak_mat)))
    )
  
  
  
  print(paste0("The peak-to-gene links matrix, restricted to a +/- 100kb window around the TSS has dimensions ", split(dim(p2g_links_gene_window), 1)))
  
  print(paste0("The maximum value is: ", max(p2g_links_gene_window), ", the minimum value is: ", min(p2g_links_gene_window) ))
  
  
  # remove any rows or columns with zeros
  p2g_links_gene_window <- p2g_links_gene_window[rowSums(p2g_links_gene_window) != 0, ]
  p2g_links_gene_window <- p2g_links_gene_window[, colSums(p2g_links_gene_window) != 0]
  
  print(paste0("After removing any rows and columsn which do not contain any links we are left with ", nrow(p2g_links_gene_window), " genes and ", ncol(p2g_links_gene_window), " peaks."))
  
  # Compute gene activity scores with weighted distance matix
  gene_window_scores <- gene_activity_scores(peak_mat_sub[colnames(p2g_links_gene_window), ], p2g_links_gene_window)

  
  return(gene_window_scores) 
}
gene_window_scores <- compute_gene_window_score(
  p2g_mat_sub = p2g_mat_sub, 
  peak_mat = PEAK_MAT, 
  links = links, 
  p2g_original = p2g, 
  gene_anno = GENE_ANNO)
## [1] "Out of 139966 peaks only 29829 peaks are found within gene window of 200kb."
## Saving 10 x 8 in image

## Saving 10 x 8 in image

## Saving 10 x 8 in image

## Saving 10 x 8 in image

## [1] "The peak-to-gene links matrix, restricted to a +/- 100kb window around the TSS has dimensions c(22273, 192251)"
## [1] "The maximum value is: 0.976679757235753, the minimum value is: 0"
## [1] "After removing any rows and columsn which do not contain any links we are left with 1512 genes and 11639 peaks."
## [1] "normalized the p2g matrix"
## [1] "Computed weightes sum of peaks for each gene and cell"
## [1] "Normalized for library size"
## [1] "Exponentiated matrix"
## [1] "Divided by total activity to get value between zero and one"

SEACells

Second, I compared the distance weigths using the SEACell aggregates, which yields better results as can be seen above.

gene_window_agg <- create_seacell_aggregates(gene_window_scores, seacells)
gene_window_corr <- rowwise_correlations(seacell_rna_agg, gene_window_agg,
                                         name = "Gene window around TSS")

gene_window_corr[[2]]

ggsave("Kathi/plots/correlation_p2g_gene_window_archr.pdf")
## Saving 6 x 6 in image
ggplot() +
  geom_point(aes(x = gene_window_corr[[1]],
                 y = seacell_corr_archr[[1]][names(gene_window_corr[[1]])])) +
  geom_density_2d_filled(aes(
    y = seacell_corr_archr[[1]][names(gene_window_corr[[1]])],
    x = gene_window_corr[[1]]), alpha = 0.5) +
  geom_line(aes(x = seacell_corr_archr[[1]][names(gene_window_corr[[1]])], 
                y = seacell_corr_archr[[1]][names(gene_window_corr[[1]])]), 
            color = "red") +
  CORR_THEME +
  labs(x = "Correlation gene expr. & p2g activity scores",
        y = "Correlation gene expression & ArchR gene activity scores",
       title = "Peak-to-gene links within gene window")

ggsave("Kathi/plots/compare_correlation_p2g_gene_window_archr.pdf")
## Saving 6 x 6 in image

Effect of using different distance decay rates

How does the distance weight distribution change with different decay rates?

Here, we use the formula \(e^{\frac{-abs(distance)}{c}}\) with differen decay rates \(c \in \{5000, 50000, 500000, 5000000\}\). Additionally, we use only peaks which overlap with a +/- 100kb window from the TSS.

model_list <- c("exp(-abs(distance)/5000)", "exp(-abs(distance)/50000)",
                "exp(-abs(distance)/500000)", "exp(-abs(distance)/5000000)")


atac_granges <- metadata(p2g)[[1]]
#rna_granges <- metadata(p2g_original)[[2]]
gene_anno <- GENE_ANNO

# create gene annotations with start coordinate of each gene
# subset to contain only genes which are included in our peak2gene matrix
gene_anno <- gene_anno %>% as.data.frame() %>%
  mutate(idxRNA = seq(nrow(.))) %>% 
  dplyr::filter(name %in% rownames(p2g_mat_sub)) %>%
  mutate(strand = ifelse(strand == 1, "+", "-")) %>%
  mutate(start_coord = ifelse(strand == "+", start, end)) %>% 
  rename(gene = name) #%>% GRanges()

# subset atac granges & get middle of each peak
pos_atac_granges <- atac_granges  %>% 
  as.data.frame() %>%
  mutate(idxATAC = seq(nrow(.))) %>% 
  # group_by(seqnames) %>%
  # mutate(idx = seq_along(seqnames)) %>% 
  # ungroup %>%
  #tidyr::unite(chr_idx, seqnames, idx, remove = FALSE, sep = "_") %>% 
  dplyr::filter(idxATAC %in% colnames(p2g_mat_sub)) %>% 
  mutate(middle = start + 300) #%>% GRanges() 



# combine the three dataframes
p2g_join <- left_join(links, as.data.frame(pos_atac_granges),
                      by = "idxATAC")
p2g_join <- left_join(p2g_join, as.data.frame(gene_anno),
                      by = "idxRNA", suffix = c(".atac", ".rna"))

# compute distance and distance weights 
p2g_join <- p2g_join %>% 
  mutate(distance = abs(start_coord - middle)) %>%
  mutate(rel_distance = start_coord - middle)
 # mutate(distance_weight = eval(parse(text=geneModel)))

distribution of distance weights using different distance decay rates

for (model in model_list){ 
# compute distance and distance weights 
  p2g_join <- p2g_join %>% 
    mutate(distance = abs(start_coord - middle)) %>%
    mutate(distance_weight = eval(parse(text=model)))
  
  p1 <- p2g_join %>% ggplot() +
    geom_histogram(aes(x = distance), bins = 200, fill="#69b3a2") +
    labs(title = "Distance between peaks and genes", x = "distance") +
    geom_vline(xintercept  = 5000, color = "red") +
    geom_vline(xintercept  = 250000, color = "orange") +
   theme(axis.text.x = element_text(size = 12),
        axis.text.y = element_text(size = 12),
        axis.title.x = element_text(size = 20), # change size of axis title
        axis.title.y = element_text(size = 20),
        plot.title = element_text(hjust = 0.5, size = 20),
        legend.position = "None", 
        panel.grid.major = element_line(colour = "grey"),   # Major grid lines
        panel.background = element_rect(fill = "white", colour = "black"),
        aspect.ratio = 1.2)
  
  p2 <- p2g_join %>% ggplot() +
    geom_histogram(aes(x = (distance_weight)), bins = 200, fill="#69b3a2") +
    scale_y_log10() +
    labs(title = paste0(model),
         x = "distance weights", y = "log10(counts)") +
  theme(axis.text.x = element_text(size = 12),
        axis.text.y = element_text(size = 12),
        axis.title.x = element_text(size = 20), # change size of axis title
        axis.title.y = element_text(size = 20),
        plot.title = element_text(hjust = 0.5, size = 20),
        legend.position = "None", 
        panel.grid.major = element_line(colour = "grey"),   # Major grid lines
        panel.background = element_rect(fill = "white", colour = "black"),
        aspect.ratio = 1.2)
  
  print(cowplot::plot_grid(p1, p2, ncol = 2))
  
  ggsave(paste0("Kathi/plots/distance_weights", model, ".pdf"))

}
## Saving 10 x 6 in image

## Saving 10 x 6 in image

## Saving 10 x 6 in image

## Saving 10 x 6 in image

  # Relationship between distance and correlation value
# p3 <- p2g_join %>% ggplot() +
#   geom_point(aes(x = Correlation, y = distance)) +
#   labs(title = "Distance vs. correlation between peaks and genes",
#        x = "Correlation between peak and gene", 
#        y = "Distance between peak and gene")
# 
# 
# p4 <- p2g_join %>% ggplot() +
#   geom_point(aes(x = Correlation, y = distance_weight)) +
#   labs(title = "Distance vs. correlation between peaks and genes",
#        x = "Correlation between peak and gene", 
#        y = "Distance weights between peak and gene")


#cowplot::plot_grid(p1, p2, ncol = 1)

Relationship between distance and correlation values


# Olot relationship between distance and correlation as density plots
p1 <- p2g_join %>% ggplot() + 
  geom_density_2d_filled(aes(x = Correlation, y = distance)) +
  theme(legend.position = "None") +
  labs(title = "Relationship between distance and correlation")

p2 <- p2g_join %>%
  filter(Correlation > 0.3) %>% 
  ggplot() + 
  geom_density_2d_filled(aes(x = Correlation, y = distance)) +
  theme(legend.position = "None") +
  labs(title = "Relationship between distance and correlation")

p3 <- p2g_join %>%
  filter(Correlation > 0.6) %>% 
  ggplot() + 
  geom_density_2d_filled(aes(x = Correlation, y = distance)) +
  theme(legend.position = "None") +
  labs(title = "Relationship between distance and correlation")

cowplot::plot_grid(p1, p2, p3, ncol = 2)
p2g %>%  
  mutate(bin=cut_width(distance, width=100000, boundary=0)) %>%
  filter(distance < 10000000) %>% 
  ggplot() +
  geom_boxplot(aes(x = bin, y = Correlation), fill="#69b3a2") +
  #geom_vline(xintercept  = 250000, color = "red") +
  labs(title = "Relationship between distance and correlation of p2g links, 100kb bins",
       x = "Distance between peaks and genes within 250kb", y = "Correlation") + 
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1))
p2g_join %>%  
  mutate(bin=cut_width(distance, width=100000, boundary=0)) %>%
  dplyr::filter(distance < 10000000) %>% 
  ggplot() +
  geom_violin(aes(x = bin, y = Correlation), fill = "#69b3a2", alpha = .6, scale = "width") +
  geom_boxplot(aes(x = bin, y = Correlation), alpha = 0) +
    #geom_vline(xintercept  = 250000, color = "red") +
  labs(title = "P2g links, entire chromsome",
       x = "Distance (100kb)", y = "Correlation") + 
  CUSTOM_THEME

  #theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1))

ggsave("Kathi/plots/relationship_dist_corr_10Mb.pdf")
## Saving 15 x 6 in image

Figures for Report

p1 <- p2g_join %>%  
  mutate(bin=cut_width(distance, width=100000, boundary=0)) %>%
  dplyr::filter(distance < 10000000 & Correlation > 0.5) %>% 
  ggplot() +
  geom_violin(aes(x = bin, y = Correlation), fill = "#69b3a2", alpha = .6, scale = "width") +
  geom_boxplot(aes(x = bin, y = Correlation), alpha = 0) +
  labs(title = "Relationship between distance and correlation of p2g links, 100kb bins",
       x = "Distance < 1e^7 bp", y = "Correlation > 0.5") + 
  scale_fill_brewer(palette="Set3") +
  CUSTOM_THEME
  #theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1))

print(p1)

ggsave("Kathi/plots/Relationship_dist_corr_diff_values_1.pdf")
## Saving 12 x 6 in image
p2 <- p2g_join %>%  
  mutate(bin=cut_width(distance, width=100000, boundary=0)) %>%
  dplyr::filter(distance < 10000000 & Correlation > 0.8) %>% 
  ggplot() +
  geom_violin(aes(x = bin, y = Correlation), fill = "#69b3a2", alpha = .6, scale = "width") +
  geom_boxplot(aes(x = bin, y = Correlation), alpha = 0) +
  labs(title = "Relationship between distance and correlation of p2g links, 100kb bins",
       x = "Distance < 1e^7 bp", y = "Correlation > 0.8") + 
  scale_fill_brewer(palette="Set3") +
  CUSTOM_THEME

print(p2)

ggsave("Kathi/plots/Relationship_dist_corr_diff_values_2.pdf")
## Saving 12 x 6 in image
p3 <- p2g_join %>%  
  mutate(bin=cut_width(distance, width=100000, boundary=0)) %>%
  dplyr::filter(distance < 10000000 & Correlation < 0.5) %>% 
  ggplot() +
  geom_violin(aes(x = bin, y = Correlation), fill = "#69b3a2", alpha = .6, scale = "width") +
  geom_boxplot(aes(x = bin, y = Correlation), alpha = 0) +
  labs(title = "Relationship between distance and correlation of p2g links, 100kb bins",
       x = "Distance < 1e^7 bp", y = "Correlation < 0.5") + 
  scale_fill_brewer(palette="Set3") +
  CUSTOM_THEME

print(p3)

ggsave("Kathi/plots/Relationship_dist_corr_diff_values_3.pdf")
## Saving 12 x 6 in image
p4 <- p2g_join %>%  
  mutate(bin=cut_width(distance, width=1000, boundary=0)) %>%
  dplyr::filter(distance < 100000) %>% # & Correlation > 0.5) %>% 
  ggplot() +
  geom_violin(aes(x = bin, y = Correlation), fill = "#69b3a2", alpha = .6, scale = "width") +
  geom_boxplot(aes(x = bin, y = Correlation), alpha = 0) +
  labs(title = "Relationship between distance and correlation of p2g links, 1kb bins",
       x = "Distance < 100kb") + 
  scale_fill_brewer(palette="Set3") +
  CUSTOM_THEME

print(p4)

ggsave("Kathi/plots/Relationship_dist_corr_diff_values_4.pdf")
## Saving 12 x 6 in image

```#{r, fig.width=15, fig.height=15} cowplot::plot_grid(p1, p2, p3, p4, ncol = 2)

```

Lets have a look at correlation values between peaks within the promoter region of a TSS, namely 5kb upstream of the TSS.

p2g_join %>%  
  mutate(bin=cut_width(rel_distance, width=100, boundary=0)) %>%
  dplyr::filter(rel_distance < 0 & rel_distance >= -5000) %>% 
  ggplot() +
  geom_violin(aes(x = bin, y = Correlation), fill = "#69b3a2", alpha = .6, scale = "width") +
  geom_boxplot(aes(x = bin, y = Correlation), alpha = 0) +
  labs(title = "Distance -5kb upstream of TSS, 100bp bins",
       x = "Distance -5kb upstream of TSS", y = "Correlation") + 
  scale_fill_brewer(palette="Set3") +
  CUSTOM_THEME

ggsave("Kathi/plots/distance_within_promoter.pdf")
## Saving 10 x 6 in image

TAD boundaries

In case Hi-C data are available, TAD boundaries could aid in finding peak-to-gene links. Setting a distance decay rate to the same value for all genes and celltypes, does not give credit to the biological variability associated with gene regulation. In (Zuin J. 2022) it has been shown experimentally, that interactions between regulatory elements decay exponentially within TAD boundaries and almost disappear completely beyond TAD boundaries. Here, I restricted the peak-to-gene links identified by ArchR to within TAD boundaries and computed gene activity scores again.

THEME_LONG <-   theme(axis.text.x = element_text(size = 12),
        axis.text.y = element_text(size = 12),
        axis.title.x = element_text(size = 15), # change size of axis title
        axis.title.y = element_text(size = 15),
        plot.title = element_text(hjust = 0.5, size = 20),
        legend.position = "None", 
        panel.grid.major = element_line(colour = "grey"),   # Major grid lines
        panel.background = element_rect(fill = "white", colour = "black"),
        aspect.ratio = 0.2)
tad_boundaries <- as.data.frame(read.table("Kathi/tad_e75.bed", header = FALSE, sep = "\t", stringsAsFactors = FALSE, quote = ""))
tad_boundaries <- tad_boundaries %>% 
  rename(seqnames = V1, start = V2, end = V3) %>% 
  GRanges()

p1 <- ggplot() + geom_histogram(aes(x = width(gene_anno %>% GRanges())), 
                                    bins = 200) +
  geom_vline(xintercept = median(width(gene_anno %>% GRanges())), 
             color = "orange") +
  labs(title = paste0("Distribution of gene size, median size = ",
                      median(width(gene_anno %>% GRanges())), " bp"),
       x = "gene size (bp)") +
  THEME_LONG

p2 <- ggplot() + geom_histogram(aes(x = width(tad_boundaries)), bins = 200) +
  geom_vline(xintercept = median(width(tad_boundaries)), color = "orange") +
  labs(title = paste0("Distribution of TAD boundary size, median size = ",
       median(width(tad_boundaries)), " bp"),
      x = "TAD boundary size (bp)") +
  THEME_LONG

cowplot::plot_grid(p1, p2, ncol = 1)

What is the distribution of peaks and genes within TAD boundaries?

gene_anno <- GENE_ANNO

# create gene annotations with start coordinate of each gene
# subset to contain only genes which are included in our peak2gene matrix
gene_anno <- gene_anno %>% as.data.frame() %>%
  mutate(idxRNA = seq(nrow(.))) %>% 
  dplyr::filter(name %in% rownames(p2g_mat_sub)) %>%
  mutate(strand = ifelse(strand == 1, "+", "-")) %>%
  mutate(start_coord = ifelse(strand == "+", start, end)) %>% 
  rename(gene = name) #%>% GRanges()


# subset atac granges & get middle of each peak
pos_atac_granges <- atac_granges  %>% 
  as.data.frame() %>%
  mutate(idxATAC = seq(nrow(.))) %>% 
  # group_by(seqnames) %>%
  # mutate(idx = seq_along(seqnames)) %>% 
  # ungroup %>%
  #tidyr::unite(chr_idx, seqnames, idx, remove = FALSE, sep = "_") %>% 
  dplyr::filter(idxATAC %in% colnames(p2g_mat_sub)) %>% 
  mutate(middle = start + 300) #%>% GRanges() 

#TODO: Filter for genes!
stopifnot(length(unique(links$idxATAC)) == dim(pos_atac_granges)[[1]])
stopifnot(length(unique(links$idxRNA)) == dim(gene_anno)[[1]])
#p2g_filt <- p2g_original %>% as.data.frame() %>% filter(gene %in% rownames(p2g_mat))


  # find overlapping peaks and gene window in chromosome-aware fashion
tad_overlaps_genes <- suppressWarnings(findOverlaps(gene_anno %>% GRanges(), 
                                              tad_boundaries))

p1 <- tad_overlaps_genes %>% as.data.frame() %>%
  group_by(subjectHits) %>%
  summarise(n = n()) %>% 
  ggplot() + geom_histogram(aes(x = n), bins = 100) +
  labs(title = "Number of highly variable genes within a tad boundary",
       x = "number of genes/tad boundary") +
  CORR_THEME

tad_overlaps_peaks <- suppressWarnings(findOverlaps(pos_atac_granges %>% GRanges(),
                                         tad_boundaries))


p2 <- tad_overlaps_peaks %>% as.data.frame() %>%
  group_by(subjectHits) %>%
  summarise(n = n()) %>% 
  ggplot() + geom_histogram(aes(x = n), bins = 100) +
  labs(title = "Number of peaks within a tad boundary",
       x = "number of peaks/tad boundary") +
  CORR_THEME


cowplot::plot_grid(p1, p2, ncol = 2)

How many p2g links are within tad boundaries?

Peak-to-gene links considered in above computations

All peak-to-gene links

```#{r, fig.width=12, fig.height=5} rm(peaks) gc(reset = TRUE)

p2g_pos <- p2g %>% as.data.frame() %>% filter(Correlation > 0) %>% unite(link, idxRNA, idxATAC, sep = “%”, remove = FALSE)

gene_anno_all <- rowData(gene_expr) %>% as.data.frame() %>% mutate(idxRNA = seq(nrow(.))) %>% filter(idxRNA %in% p2g_pos$idxRNA) %>% mutate(strand = ifelse(strand == 1, “+”, “-”)) %>% mutate(start_coord = ifelse(strand == “+”, start, end)) %>% rename(gene = name) #%>% GRanges()

subset atac granges & get middle of each peak

pos_atac_granges_all <- metadata(p2g)[[1]] %>% as.data.frame() %>% mutate(idxATAC = seq(nrow(.))) %>% # group_by(seqnames) %>% # mutate(idx = seq_along(seqnames)) %>% # ungroup %>% #tidyr::unite(chr_idx, seqnames, idx, remove = FALSE, sep = "_") %>% filter(idxATAC %in% p2g_pos$idxATAC) %>% mutate(middle = start + 300) #%>% GRanges()

combine the three dataframes

p2g_join_all <- left_join(p2g_pos, as.data.frame(pos_atac_granges_all), by = “idxATAC”) p2g_join_all <- left_join(p2g_join_all, as.data.frame(gene_anno_all), by = “idxRNA”, suffix = c(“.atac”, “.rna”))

p2g_join_all <- p2g_join_all %>% mutate(distance = abs(start_coord - middle))

# find overlapping peaks and gene window in chromosome-aware fashion tad_overlaps_genes <- suppressWarnings(findOverlaps(gene_anno_all %>% GRanges(), tad_boundaries))

get genes which are not found within two TAD boundaries, but only within one

within_genes <- (tad_overlaps_genes %>% as.data.frame() %>% group_by(queryHits) %>% summarise(n = n()) %>% ungroup() %>% filter(n < 2))$queryHits

print(paste0(“Out of”, nrow(gene_anno_all), " genes, “, length(unique(queryHits(tad_overlaps_genes))),” genes are within TAD boundaries. Some of these genes even span across TAD boudnaries, namely “, abs(length(within_genes) - length(unique(queryHits(tad_overlaps_genes)))),”."))

We only keep genes within boundaries, but not genes crossing boundaries

tad_overlaps_genes <- tad_overlaps_genes %>% as.data.frame %>% filter(queryHits %in% within_genes) #%>% S4Vectors::as()

get peaks overlapping with tad boundaries

tad_overlaps_peaks <- suppressWarnings(findOverlaps(pos_atac_granges_all %>% GRanges(), tad_boundaries))

filter for peaks overlapping tad boundaries which also contain genes

tad_overlaps_peaks <- tad_overlaps_peaks %>% as.data.frame() %>% filter(subjectHits %in% tad_overlaps_genes$subjectHits)

combine tad boundaries which contain genes and peaks

tad_combine <- left_join(tad_overlaps_genes, tad_overlaps_peaks, copy = TRUE, by = “subjectHits”, suffix = c(“.gene”, “.peak”)) %>% unite(link, queryHits.gene, queryHits.peak, sep = “%”, remove = FALSE)

genes <- gene_anno_all[tad_combine$queryHits.gene, ] %>% mutate(tad_index = tad_combine$subjectHits)

peak_coll <- pos_atac_granges_all[tad_combine$queryHits.peak, ] %>% mutate(tad_index = tad_combine$subjectHits)

gene_peak_tad_df <- left_join(genes, peak_coll, by = “tad_index”, suffic = c(“.gene”, “.peak”)) %>% unite(peak_gene_tad, gene, idxATAC, sep = “#”, remove = FALSE)

some plots

p1 <- (tad_overlaps_peaks %>% as.data.frame() %>% group_by(subjectHits) %>% # gene region summarize(n = n()) %>% # get number of peaks overlapping with a gene region ggplot() + geom_histogram(aes(x = n), bins = 100, fill=“#69b3a2”) + labs(title = “Number of peaks per tad boundary, positive p2g links”, x = “number of peaks”))

p2 <- (tad_overlaps_genes %>% as.data.frame() %>% group_by(subjectHits) %>% # gene region summarize(n = n()) %>% # get number of peaks overlapping with a gene region ggplot() + geom_histogram(aes(x = n), bins = 100, fill=“#69b3a2”) + labs(title = “Number of genes per tad boundary, positive p2g links”, x = “number of genes”))

print(cowplot::plot_grid(p1, p2, ncol = 2))

print(paste0(“The number of positive peak-to-gene links is:”, length(p2g_pos\(link))) print(paste0( "The number of positive peak-to-gene links within TAD boundaries is: ", length(tad_combine\)link)))

print(paste0(“The number of positive peak-to-gene links outside TAD boundaries is:”, length(p2g_pos\(link) - length(tad_combine\)link)))

print(paste0(“The proportion of peak-to-gene links within TAD boundaries out of all positive peak-to-gene links across the entire chromosome is”, round(length(tad_combine\(link) / length(p2g_pos\)link), 5)))

#ggplot() + geom_point(aes(x = p2g_pos\(idxATAC, y = p2g_pos\)idxRNA))

```

Distance vs. Correlation

Here I visualize the relationship between distance between peaks and genes and their respective correlation values using all positive links obtained using ArchR

p2g_join_all %>%  
  mutate(bin=cut_width(distance, width=100000, boundary=0)) %>%
  filter(distance < 10000000) %>% 
  ggplot() +
  geom_boxplot(aes(x = bin, y = Correlation), fill="#69b3a2") +
  #geom_vline(xintercept  = 250000, color = "red") +
  labs(title = "Relationship between distance and correlation of p2g links, 100kb bins",
       x = "Distance between peaks and genes within 250kb", y = "Correlation") + 
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1))
colPalette_celltypes = c('#532C8A',
 '#c19f70',
 '#f9decf',
 '#c9a997',
 '#B51D8D',
 '#3F84AA',
 '#9e6762',
 '#354E23',
 '#F397C0',
 '#ff891c',
 '#635547',
 '#C72228',
 '#f79083',
 '#EF4E22',
 '#989898',
 '#7F6874',
 '#8870ad',
 '#647a4f',
 '#EF5A9D',
 '#FBBE92',
 '#139992',
 '#cc7818',
 '#DFCDE4',
 '#8EC792',
 '#C594BF',
 '#C3C388',
 '#0F4A9C',
 '#FACB12',
 '#8DB5CE',
 '#1A1A1A',
 '#C9EBFB',
 '#DABE99',
 '#65A83E',
 '#005579',
 '#CDE088',
 '#f7f79e',
 '#F6BFCB')

tad_boundaries %>% as.data.frame() %>% group_by(seqnames) %>% 
  summarise(n = n()) %>% ungroup() %>%  
  ggplot() + geom_col(aes(x = seqnames, y = n),  color = "black", alpha = .6) +#, fill = seqnames), alpha = .7) +#, position = "dodge")
  theme(legend.position = "None") +
  scale_fill_manual(values = colPalette_celltypes) +
  labs(y = "number of tad boundaries", x = "chromosome") + 
  CUSTOM_THEME

TODO: Should I also remove peaks which are across TAD boundaries?

# As input for this function it is best to use only the most highly variable genes
tad_boundaries_p2g_scores <- function(p2g_mat_sub, peak_mat, links, p2g_original, gene_anno, tad_boundaries){
  atac_granges <- metadata(p2g_original)[[1]]
  #rna_granges <- metadata(p2g_original)[[2]]
  gene_anno_original <- gene_anno
  
  # create gene annotations with start coordinate of each gene
  # subset to contain only genes which are included in our peak2gene matrix
  gene_anno <- gene_anno %>% as.data.frame() %>%
    mutate(idxRNA = seq(nrow(.))) %>% 
    dplyr::filter(name %in% rownames(p2g_mat_sub)) %>%
    mutate(strand = ifelse(strand == 1, "+", "-")) %>%
    mutate(start_coord = ifelse(strand == "+", start, end)) %>% 
    rename(gene = name) #%>% GRanges()


  # subset atac granges & get middle of each peak
  pos_atac_granges <- atac_granges  %>% 
    as.data.frame() %>%
    mutate(idxATAC = seq(nrow(.))) %>% 
    # group_by(seqnames) %>%
    # mutate(idx = seq_along(seqnames)) %>% 
    # ungroup %>%
    #tidyr::unite(chr_idx, seqnames, idx, remove = FALSE, sep = "_") %>% 
    dplyr::filter(idxATAC %in% colnames(p2g_mat_sub)) %>% 
    mutate(middle = start + 300) #%>% GRanges() 
  
  #TODO: Filter for genes!
  stopifnot(length(unique(links$idxATAC)) == dim(pos_atac_granges)[[1]])
  stopifnot(length(unique(links$idxRNA)) == dim(gene_anno)[[1]])
  #p2g_filt <- p2g_original %>% as.data.frame() %>% filter(gene %in% rownames(p2g_mat))
  
  
    # find overlapping peaks and gene window in chromosome-aware fashion
  tad_overlaps_genes <- suppressWarnings(findOverlaps(gene_anno %>% GRanges(), 
                                                tad_boundaries))
  
  # get genes which are not found within two TAD boundaries, but only within one
  within_genes <- (tad_overlaps_genes %>% 
  as.data.frame() %>% 
  group_by(queryHits) %>%
  summarise(n = n()) %>% ungroup() %>%
  dplyr::filter(n < 2))$queryHits

  print(paste0("Out of ", nrow(gene_anno), " genes, ", length(unique(queryHits(tad_overlaps_genes))), " genes are within TAD boundaries. Some of these genes even span across TAD boudnaries, namely ", length(within_genes), "."))
  
  # We only keep genes within boundaries, but not genes crossing boundaries
  tad_overlaps_genes <- tad_overlaps_genes %>% as.data.frame %>% 
    dplyr::filter(queryHits %in% within_genes) #%>% S4Vectors::as()
  
  # get peaks overlapping with tad boundaries
  tad_overlaps_peaks <- suppressWarnings(findOverlaps(pos_atac_granges %>% GRanges(),
                                         tad_boundaries))
  
  # filter for peaks overlapping tad boundaries which also contain genes
  tad_overlaps_peaks <- tad_overlaps_peaks %>% as.data.frame() %>% 
    dplyr::filter(subjectHits %in% tad_overlaps_genes$subjectHits)
  
  # combine tad boundaries which contain genes and peaks
  tad_combine <- left_join(tad_overlaps_genes, tad_overlaps_peaks, 
                           copy = TRUE, by = "subjectHits", suffix = c(".gene", ".peak"))
  
  
  genes <- gene_anno[tad_combine$queryHits.gene, ] %>%
    mutate(tad_index = tad_combine$subjectHits)
  
  peak_coll <- pos_atac_granges[tad_combine$queryHits.peak, ] %>% 
    mutate(tad_index = tad_combine$subjectHits)
  
  gene_peak_tad_df <- left_join(genes, peak_coll, by = "tad_index", suffic = c(".gene", ".peak")) %>%  unite(peak_gene_tad, gene, idxATAC, sep = "#", remove = FALSE)


  
  ### some plots
  p1 <- (tad_overlaps_peaks  %>% as.data.frame() %>% 
         group_by(subjectHits) %>% # gene region
         summarize(n = n()) %>% # get number of peaks overlapping with a gene region
         ggplot() + geom_histogram(aes(x = n), bins = 100, fill="#69b3a2") +
         labs(title = "Number of peaks / TAD boundary",
             x = "number of peaks")) +
    CORR_THEME
  
  p2 <- (tad_overlaps_genes  %>% as.data.frame() %>% 
       group_by(subjectHits) %>% # gene region
       summarize(n = n()) %>% # get number of peaks overlapping with a gene region
       ggplot() + geom_histogram(aes(x = n), bins = 100, fill="#69b3a2") +
       labs(title = "Number of hvg genes / TAD boundary",
           x = "number of genes")) +
    CORR_THEME
  
  print(cowplot::plot_grid(p1, p2, ncol = 2))
  
  ggsave("Kathi/plots/tad_boundaries_number_peaks_genes.pdf")
  
  # combine the annotation dataframe with the p2g links dataframe
  p2g_join <- left_join(links, as.data.frame(pos_atac_granges),
                        by = "idxATAC")
  p2g_join <- left_join(p2g_join, as.data.frame(gene_anno),
                        by = "idxRNA", suffix = c(".atac", ".rna"))

  # compute distance 
  p2g_join <- p2g_join %>% 
    mutate(distance = abs(start_coord - middle), 
           rel_distance = start_coord - middle)
  
  # filter for the p2g links within tad boundaries
  corr_tad_boundary <- p2g_join %>% 
    unite(peak_gene_tad, gene, idxATAC, sep = "#", remove = FALSE) %>% 
    dplyr::filter(peak_gene_tad %in% gene_peak_tad_df$peak_gene_tad)

  ### PLOTS
  
  p1 <- corr_tad_boundary %>% 
    ggplot() +
    geom_histogram(aes(x = Correlation), bins = 200, fill = "#69b3a2") +
    labs(title = "P2g links within TAD boundaries") +
    THEME_LONG
  
  p2 <- corr_tad_boundary %>% 
    ggplot() +
    geom_histogram(aes(x = distance), bins = 200, fill = "#69b3a2") +
    labs(x = "Distance (bp)") +
    THEME_LONG
  
  p3 <- corr_tad_boundary %>% 
    mutate(bin = cut_width(distance, width=100000, boundary=0)) %>% 
    ggplot() +
    geom_violin(aes(x = bin, y = Correlation), fill = "#69b3a2", alpha = .6, scale = "width") +
    geom_boxplot(aes(x = bin, y = Correlation), alpha = 0) +
    labs(title = "Distance vs. Correlation, within TAD boundaries",
         x = "Distance (100kb bins)") +
    scale_x_discrete(guide = guide_axis(angle = 45)) +
    THEME_LONG

  print(cowplot::plot_grid(p1, p2, ncol = 1))
  
  ggsave("Kathi/plots/Distance_corr_tad.pdf")
  
  print(p3)
  ggsave("Kathi/plots/Distance_vs_corr.pdf")

  
  #### PLOT
  p1 <- corr_tad_boundary %>% ggplot() +
    geom_histogram(aes(x = rel_distance), bins = 500, fill = "#69b3a2") + 
    scale_y_log10() +
    labs(title = "P2g links within tad boundaries",
         x = "Relative distance to TSS (bp)", y = "log10(count)") + 
    geom_vline(xintercept = c(100000, -100000), color = "orange") +
    CORR_THEME
  
  print(p1)
  ggsave("Kathi/plots/Relative_distance_tad.pdf")

  
  
  p2g_links_tad <- Matrix::sparseMatrix(
      i = corr_tad_boundary$idxRNA, 
      j = corr_tad_boundary$idxATAC, 
      x = corr_tad_boundary$Correlation, 
      dims = c(nrow(gene_anno_original), nrow(peak_mat)),
      dimnames = list(gene_anno_original$name,rownames(peak_mat))
    )
  
  
  print(paste0("The maximum value is: ", max(p2g_links_tad), ", the minum value is: ", min(p2g_links_tad) ))
  
  
  
  p2g_links_tad <- p2g_links_tad[rowSums(p2g_links_tad) != 0, ]
  p2g_links_tad <- p2g_links_tad[, colSums(p2g_links_tad) != 0]
  
  print(paste0("After removing any rows and columsn which do not contain any links we are left with ", nrow(p2g_links_tad), " genes and ", ncol(p2g_links_tad), " peaks."))
  
  
  # Compute gene activity scores
  tad_scores <- gene_activity_scores(peak_mat_sub[colnames(p2g_links_tad), ], p2g_links_tad)
  
  return(tad_scores) 
}
gc(reset = TRUE)
##              used    (Mb)  gc trigger    (Mb)   max used    (Mb)
## Ncells    7426147   396.6    22484560  1200.9    7426147   396.6
## Vcells 6815565046 51998.7 11148116592 85053.4 6815565046 51998.7
tad_scores <- tad_boundaries_p2g_scores(p2g_mat_sub = p2g_mat_sub,
                                        peak_mat = PEAK_MAT,
                                        links = links, 
                                        p2g_original = p2g, 
                                        gene_anno = GENE_ANNO,
                                        tad_boundaries = tad_boundaries)
## [1] "Out of 1710 genes, 1522 genes are within TAD boundaries. Some of these genes even span across TAD boudnaries, namely 1433."
## Saving 10 x 6 in image

## Saving 10 x 6 in image

## Warning: Groups with fewer than two data points have been dropped.
## Groups with fewer than two data points have been dropped.
## Saving 10 x 6 in image
## Warning: Groups with fewer than two data points have been dropped.
## Groups with fewer than two data points have been dropped.

## Warning: Transformation introduced infinite values in continuous y-axis
## Warning: Removed 140 rows containing missing values (geom_bar).
## Saving 10 x 6 in image
## Warning: Transformation introduced infinite values in continuous y-axis
## Removed 140 rows containing missing values (geom_bar).

## [1] "The maximum value is: 0.976679757235753, the minum value is: 0"
## [1] "After removing any rows and columsn which do not contain any links we are left with 1346 genes and 21964 peaks."
## [1] "normalized the p2g matrix"
## [1] "Computed weightes sum of peaks for each gene and cell"
## [1] "Normalized for library size"
## [1] "Exponentiated matrix"
## [1] "Divided by total activity to get value between zero and one"
gc(reset = TRUE)
##              used    (Mb)  gc trigger    (Mb)   max used    (Mb)
## Ncells    7839638   418.7    22484560  1200.9    7839638   418.7
## Vcells 7460719634 56920.8 11148116592 85053.4 7460719634 56920.8
gene_window_agg <- create_seacell_aggregates(tad_scores, seacells)
gene_window_corr <- rowwise_correlations(seacell_rna_agg, gene_window_agg,
                                         name = "Gene window around TSS")

gene_window_corr[[2]]

ggplot() +
  geom_point(aes(y = seacell_corr_archr[[1]][names(gene_window_corr[[1]])], 
                 x =gene_window_corr[[1]]))  +
  geom_density_2d_filled(aes(y = seacell_corr_archr[[1]][names(gene_window_corr[[1]])],
                             x = gene_window_corr[[1]]), alpha = 0.5) +
  geom_line(aes(x = seacell_corr_archr[[1]][names(gene_window_corr[[1]])], 
                y = seacell_corr_archr[[1]][names(gene_window_corr[[1]])], 
                color = "red")) +
  labs(x = "Correlation gene expr. & p2g activity scores",
        y = "Correlation gene expr. & ArchR gene activity scores", 
       title = "P2g links within TAD boundaries") +
  CORR_THEME

ggplot() +
  geom_point(aes(y = seacell_corr_p2g[[1]][names(gene_window_corr[[1]])], 
                 x =gene_window_corr[[1]]))  +
  geom_density_2d_filled(aes(y = seacell_corr_p2g[[1]][names(gene_window_corr[[1]])],
                             x = gene_window_corr[[1]]), alpha = 0.5) +
  geom_line(aes(x = seacell_corr_p2g[[1]][names(gene_window_corr[[1]])], 
                y = seacell_corr_p2g[[1]][names(gene_window_corr[[1]])], 
                color = "red")) +
  labs(x = "Correlation gene_expr. & p2g links within TAD boundaries",
        y = "Correlation gene expr. & all p2g links ", 
       title = "P2g links within TAD boundaries vs. all links") +
  CORR_THEME

Adapted Archr Gene Activity Score function

ArchR provides a function to compute gene activity scores based on accessibility in the regions around the gene. For this a tile matrix is used. This tile matrix is a matrix where the genome is divided into bins of 500bp. If there is a Tn5 insertion in a bin the entry will be 1, if there is no insertion the entry will be 0. Importantly, they compared their function to 52 other functions and found their own function to be the best performing.

Here I tried to better understand how this function works and changed the source code of the ArchR function to also take peak matrix as input and compute the gene activity based on peaks, rather than based on tiles. Additionally, I adapted the funciton in a way such that it takes tad boundaries as input and uses all peaks which are within the same tad boundary as a gene to compute the activity scores.

There are two different options for computing gene activity scores in ArchR. First, we can use the TSS and create a gene window around it (+/- 100kp of TSS). All insertions found within tiles within this gene window will be accumulated for the gene activity scores. If we set the option ‘useGeneBoundaries=TRUE’ then we will make sure that no regions overlap between any two genes. If the gene window of one gene overlaps with the gene window of another gene, those tiles are not considered anymore. The disadvantage of this approac is that genes can be very large (>100bp), meaning that in some cases the 100kp extension downstream of the TSS would not even contain the entire gene body.

Second, we can use the entire gene body and extend the gene window beyond the start and end coordinates of the gene body. Importantly, the gene body is extended 5kb upstream of the TSS, to also include the promoter region. Using the entire gene body instead of only the TSS can be achieved by setting ‘useTSS=FALSE’. In this approach the gene window is created by extending -100kb upstream of the TSS -5kb and +100kb downstream of the gene end coordinate. This way, the entire gene body will be included in the gene window. An unwanted consequence of this might be that very large genes could bias the gene activity scores. Therefore ArchR introduces a weight for the inverse of the gene body size according to:

\(w = \frac{1}{gene size}\) with \(w\) being the inverse of the gene size. $

geneRegions\(geneWeight = 1 + w * (geneScaleFactor - 1) / (max(w) - min(w))\). The default geneScaleFactor is 5.

Additionally, ArchR uses a distance weight. Farther away tiles/peaks are less likely to interact with a TSS than closer tiles/peaks. If the first approach, using only the TSS, the distance weights are computed as follows:

\(weight = e^{-(abs(distTSS/5000))}\) with \(distTSS\) being the distance from the TSS. This way the weights decay exponentially with distance. The constant value of \(5000\) is a parameter which could be optimized for different genes or datasets, but here we will keep it constant.

In case the entire gene body is used, the distance weights are kept constant for all tiles/peaks within the gene body and only decay beyond the gene body.

\(weight = \begin{cases} if (-5kb from TSS, TTS): 1 + e^{-1} \\ else: e^{-abs(distGB/5000) + e^{-1}} \end{cases}\)

ArchR Gene Activity Scores using TAD boundaries

Instead of using a +/-100kb window around the gene body, in the adapted function all peaks which are within the same TAD boundary as the gene of interest are considered for the activity score of that gene. The distance weight with c = 5000 is kept the same as for the default ArchR function. As can be seen below, extending the gene window to TAD boundaries yields very similar results compared to the default ArchR function.

proj <- loadArchRProject("Kathi/06_gene_activity_scores/")

proj <- addTADGeneScoreMatrix(
  proj,
  genes = getGenes(proj),
  peaks = getPeakSet(proj),
  tadBoundaries = tad_boundaries,
  geneModel = "exp(-abs(x)/500000) + exp(-1)",
  matrixName = "GeneScoreMatrix_tads_500k",
  extendUpstream = c(1000, 100000),
  extendDownstream = c(1000, 100000),
  geneUpstream = 5000, #New Param
  #geneDownstream = 0, #New Param
  useGeneBoundaries = FALSE,
  useTSS = FALSE, #New Param
  extendTSS = FALSE,
  tileSize = 500,
  ceiling = 4,
  geneScaleFactor = 5, #New Param
  scaleTo = 10000,
  excludeChr = c("chrY", "chrX", "chrM"),
  blacklist = getBlacklist(proj),
  threads = 1,
  parallelParam = NULL,
  subThreading = TRUE,
  force = TRUE,
  logFile = createLogFile(".addTADGeneScoreMat"))

scores <- getMatrixFromProject(proj, useMatrix = "GeneScoreMatrix")
score_mat <- assays(scores)[[1]]
rownames(score_mat) <- rowData(scores)$name


#saveRDS(scores, "tad_scores")
ggplot() +
  geom_histogram(aes(x = rowSums(score_mat)), bins = 200)
# compute aggregates of ArchR gene activity score matrix
default_archr <- create_seacell_aggregates(archr_scores_mat,
                                           seacells)
# compute aggregates for tad boundary ArchR gene activity score matrix
tad_archr <- create_seacell_aggregates(score_mat, seacells)
# compute aggregates of gene expression matrix
rna_hvg <- create_seacell_aggregates(expr_sub, seacells)

# correlation between gene expression values and default Archr gene activity scores
default_archr_corr <- rowwise_correlations(rna_hvg, default_archr, 
                                           "ArchR gene activity scores, SEAcells")
# correlation between gene expression and TAD boundary gene activity scores
tad_corr <- rowwise_correlations(rna_hvg, tad_archr, "ArchR gene activity scores within TAD boundaries, SEACells")

cowplot::plot_grid(default_archr_corr[[2]], tad_corr[[2]], ncol = 2)

ggplot() +
  geom_point(aes(x = tad_corr[[1]], y = default_archr_corr[[1]][names(tad_corr[[1]])])) +
  geom_density_2d_filled(aes(x = tad_corr[[1]], 
                             y = default_archr_corr[[1]][names(tad_corr[[1]])]),
                         alpha = .5) +
  geom_line(aes(x = default_archr_corr[[1]], y = default_archr_corr[[1]]), col = "red") +
  theme(legend.position = "None")  +
  labs(x = "Correlation gene expression & ArchR TAD boundary scores",
        title = "Restricting ArchR scores to within TAD boundaries",
        y = "Correlation gene expression & ArchR gene activity scores")

TAD boundares E7.5

Since the TAD boundaries used here, are from gastrulation day E7.5. For the later time points no TAD boundaries are available. Therefore, in the following I will check if the results improve in comparison to the default ArchR function when using only data from E7.5. Since during gastrulation TAD boundaries might still be very dynamic the improving effect of TAD boundaries could be diluted by later time points in the data.

What are th genes which get zero activity scores? Do they lie outside the TAD boundaries?

e75_meta <- colData(scores) %>% as.data.frame() %>%
  filter(Sample %in% c("E7.5_rep1", "E7.5_rep2")) %>% 
  rownames_to_column("cell")
mat_75 <- score_mat[rownames(score_mat) %in% rownames(expr_sub), e75_meta$cell]
seacells_sub <- seacells %>% filter(index %in% colnames(mat_75)) 

# compute aggregates of ArchR gene activity score matrix
default_archr <- create_seacell_aggregates(archr_scores_mat[rownames(archr_scores_mat) %in%
                                                              rownames(expr_sub), 
                                                            e75_meta$cell],
                                           seacells_sub)
# compute aggregates for tad boundary ArchR gene activity score matrix
tad_archr <- create_seacell_aggregates(mat_75, seacells_sub)
# compute aggregates of gene expression matrix
rna_hvg <- create_seacell_aggregates(expr_sub[, e75_meta$cell], seacells_sub)

# correlation between gene expression values and default Archr gene activity scores
default_archr_corr <- rowwise_correlations(rna_hvg, default_archr, 
                                           "ArchR gene activity scores, SEAcells")
# correlation between gene expression and TAD boundary gene activity scores
tad_corr <- rowwise_correlations(rna_hvg, tad_archr, "ArchR gene activity scores within TAD boundaries, SEACells")

cowplot::plot_grid(default_archr_corr[[2]], tad_corr[[2]], ncol = 2)

ggplot() +
  geom_point(aes(x = tad_corr[[1]], y = default_archr_corr[[1]][names(tad_corr[[1]])])) +
  geom_density_2d_filled(aes(x = tad_corr[[1]], 
                             y = default_archr_corr[[1]][names(tad_corr[[1]])]),
                         alpha = .5) +
  geom_line(aes(x = default_archr_corr[[1]], y = default_archr_corr[[1]]), col = "red") +
  theme(legend.position = "None")  +
  labs(x = "Correlation gene expression & ArchR TAD boundary scores",
        title = "Restricting ArchR scores to within TAD boundaries",
        y = "Correlation gene expression & ArchR gene activity scores")

What are the genes which get zero correlation with gene expression?

There are 8 genes which get zero correlation values between gene activity scores and gene expression. This is, because they get zero activity scores in all cells. However, the same genes are expressed to certain levels according to the gene expression matrix. Two of the genes also get zero activity scores in the default ArchR function (Prl2c3, Gsdmc4). The reason for is not immediately clear, since as long as there are peaks in a gene window, the distance weight will at least be 0.36 accorindg to the formula. One reason for zero values could be that these genes lie outside TAD boundaries wich is in fact the case for four out of 8 genes.

What is the explanation why Lyz2 and Gm13547 get activity scores of zero?

zero_genes <- names(tad_corr[[1]][tad_corr[[1]] == 0])

zero_mat <- score_mat[zero_genes, ]
rowSums(zero_mat) 


# check the default ArchR scores for these genes
rowSums(archr_scores_mat[zero_genes, ])

# check the gene expression coutns for these genes
rowSums(expr_mat[zero_genes,])


p2g_pos <- p2g %>% as.data.frame() %>% filter(Correlation > 0) %>%
  unite(link, idxRNA, idxATAC, sep = "%", remove = FALSE)

gene_anno_all <- rowData(gene_expr) %>% as.data.frame() %>%
  mutate(idxRNA = seq(nrow(.))) %>% 
  filter(idxRNA %in% p2g_pos$idxRNA) %>%
  mutate(strand = ifelse(strand == 1, "+", "-")) %>%
  mutate(start_coord = ifelse(strand == "+", start, end)) %>% 
  rename(gene = name) #%>% GRanges()

# subset atac granges & get middle of each peak
pos_atac_granges_all <- metadata(p2g)[[1]]  %>% 
  as.data.frame() %>%
  mutate(idxATAC = seq(nrow(.))) %>% 
  # group_by(seqnames) %>%
  # mutate(idx = seq_along(seqnames)) %>% 
  # ungroup %>%
  #tidyr::unite(chr_idx, seqnames, idx, remove = FALSE, sep = "_") %>% 
  filter(idxATAC %in% p2g_pos$idxATAC) %>% 
  mutate(middle = start + 300) #%>% GRanges() 



# combine the three dataframes
p2g_join_all <- left_join(p2g_pos, as.data.frame(pos_atac_granges_all),
                      by = "idxATAC")
p2g_join_all <- left_join(p2g_join_all, as.data.frame(gene_anno_all),
                      by = "idxRNA", suffix = c(".atac", ".rna"))


p2g_join_all <- p2g_join_all %>% 
  mutate(distance = abs(start_coord - middle))



  # find overlapping peaks and gene window in chromosome-aware fashion
tad_overlaps_genes <- (findOverlaps(gene_anno_all %>% GRanges(), 
                                              tad_boundaries))


# get all genes which are found within tad boudnaries
gene_anno_within_tad <- gene_anno_all[queryHits(tad_overlaps_genes),]


# Lets examine the genes which are found within tad boundaries, but
# get an activity score of zero nevertheless
gene_anno_within_tad %>% filter(gene %in% zero_genes)


gene_name = "Lyz2"
chr_name = "chr2"
chrx <- tad_boundaries %>% as.data.frame() %>% filter(seqnames == chr_name) %>%GRanges()
hits <- findOverlaps(gene_anno_all %>% filter(gene == gene_name) %>% GRanges(),  chrx)
start_tad <- start(chrx[subjectHits(hits),])
end_tad <- end(chrx[subjectHits(hits),])
start_gene <- start(gene_anno_all %>% filter(gene == gene_name) %>% GRanges())
end_gene <- end(gene_anno_all %>% filter(gene == gene_name) %>% GRanges())
print(paste0("Out of ", length(zero_genes), " genes,  ",  length(zero_genes[zero_genes %in% gene_anno_within_tad$gene]) , " genes are found within tad boundaries, while the rest are not."))
pos_atac_granges_all %>% as.data.frame() %>% filter(seqnames == chr_name) %>%
  filter(start > start_tad & end < end_tad)

# 
# zero_genes
# 
# idx <- (gene_anno_all %>% filter(gene %in% zero_genes))$idxRNA
# 
# idx %in% gene_anno_all[tad_overlaps_genes$queryHits,

ArchR Gene Activity Scores using gene body

ArchR Gene Activity Scores using gene body


#saveArchRProject(ArchRProj = proj, outputDirectory = "12_Copy4/", load = FALSE)
loadArchRProject("12_activity_scores_gene_body_peaks/")

proj <- addKathiGeneScoreMatrix(
  proj,
  genes = getGenes(proj),
  peaks = getPeakSet(proj),
  geneModel = "exp(-abs(x)/5000) + exp(-1)",
  matrixName = "GeneScoreMatrix",
  extendUpstream = c(1000, 100000),
  extendDownstream = c(1000, 100000),
  #geneUpstream = 5000, #New Param
  #geneDownstream = 0, #New Param
  useGeneBoundaries = TRUE,
  useTSS = FALSE, #New Param
  extendTSS = FALSE,
  tileSize = 500,
  ceiling = 4,
  geneScaleFactor = 5, #New Param
  scaleTo = 10000,
  excludeChr = c("chrY", "chrM"),
  blacklist = getBlacklist(proj),
  threads = 1,
  parallelParam = NULL,
  subThreading = TRUE,
  force = TRUE,
  logFile = createLogFile(".addKathiGeneScoreMat"))


scores <- getMatrixFromProject(proj, useMatrix = "GeneScoreMatrix")

scores_mat <- assays(scores)[[1]]
rownames(scores_mat) <- rowData(scores)$name


# sce <- SingleCellExperiment(list(scores=scores_mat),
#                           rowData = as.data.frame(rowData(scores)),
#                           colData = as.data.frame(colnames(scores_mat)))
# 
# writeH5AD(sce, "/omics/groups/OE0533/internal/katharina/scDoRI/gastrulation_data/jupyter_notebooks/p2g_gene_activity_scores/archr_scores_gene_body_peak_based", X_name = "scores")

Correlating gene expression with activity scores:

archr_gene_body_agg <- knn_aggregates(scores_mat, cell_agg_list)

gene_body_knn <- rowwise_correlations(rna_agg, archr_gene_body_agg, "ArchR gene activity scores based on peak matrix, using gene body")


cowplot::plot_grid(archr_knn[[2]], gene_body_knn[[2]], ncol = 2)

p1 <- ggplot() + geom_density_2d_filled(aes(x = gene_body_knn[[1]], 
                                      y = archr_knn[[1]]), alpha = .5) +
  geom_point(aes(x = gene_body_knn[[1]], y = archr_knn[[1]])) +
  geom_line(aes(x = gene_body_knn[[1]], y = gene_body_knn[[1]]), col = "red") +
  theme(legend.position = "None") 

ArchR Gene Activity Scores using TSS, no gene body

ArchR Gene Activity Scores using TSS, no gene body


proj <- loadArchRProject("12_activity_scores_TSS_tiles/")

proj <- addGeneScoreMatrix(
  proj,
  genes = getGenes(proj),
  geneModel = "exp(-abs(x)/5000)",
  matrixName = "GeneScoreMatrix",
  extendUpstream = c(1000, 100000),
  extendDownstream = c(1000, 100000),
  #geneUpstream = 5000, #New Param
  #geneDownstream = 0, #New Param
  useGeneBoundaries = TRUE,
  useTSS = TRUE, #New Param
  extendTSS = FALSE,
  tileSize = 500,
  ceiling = 4,
  geneScaleFactor = 5, #New Param
  scaleTo = 10000,
  excludeChr = c("chrY", "chrM"),
  blacklist = getBlacklist(proj),
  threads = 1,
  parallelParam = NULL,
  subThreading = TRUE,
  force = TRUE,
  logFile = createLogFile(".addGeneScoreMatrix"))


scores <- getMatrixFromProject(proj, useMatrix = "GeneScoreMatrix")

scores_mat <- assays(scores)[[1]]
rownames(scores_mat) <- rowData(scores)$name


# sce <- SingleCellExperiment(list(scores=scores_mat),
#                           rowData = as.data.frame(rowData(scores)),
#                           colData = as.data.frame(colnames(scores_mat)))
# 
# writeH5AD(sce, "/omics/groups/OE0533/internal/katharina/scDoRI/gastrulation_data/jupyter_notebooks/p2g_gene_activity_scores/archr_scores_tss", X_name = "scores")

ArchR gene activity scores computed using TSS, no gene body and PeakMatrix instead of TileMatrix

ArchR gene activity scores computed using TSS, no gene body and PeakMatrix instead of TileMatrix

proj <- loadArchRProject("12_activity_scores_TSS_peaks/")

proj <- addKathiGeneScoreMatrix(
  proj,
  genes = getGenes(proj),
  peaks = getPeakSet(proj),
  geneModel = "exp(-abs(x)/5000)",
  matrixName = "GeneScoreMatrix",
  extendUpstream = c(1000, 100000),
  extendDownstream = c(1000, 100000),
  #geneUpstream = 5000, #New Param
  #geneDownstream = 0, #New Param
  useGeneBoundaries = TRUE,
  useTSS = TRUE, #New Param
  extendTSS = FALSE,
  tileSize = 500,
  ceiling = 4,
  geneScaleFactor = 5, #New Param
  scaleTo = 10000,
  excludeChr = c("chrY", "chrM"),
  blacklist = getBlacklist(proj),
  threads = 1,
  parallelParam = NULL,
  subThreading = TRUE,
  force = TRUE,
  logFile = createLogFile(".addKathiGeneScoreMat"))

scores <- getMatrixFromProject(proj, useMatrix = "GeneScoreMatrix")

scores_mat <- assays(scores)[[1]]
rownames(scores_mat) <- rowData(scores)$name

#
# sce <- SingleCellExperiment(list(scores=scores_mat),
#                           rowData = as.data.frame(rownames(scores_mat)),
#                           colData = as.data.frame(colnames(scores_mat)))
# 
# writeH5AD(sce, "/omics/groups/OE0533/internal/katharina/scDoRI/gastrulation_data/jupyter_notebooks/p2g_gene_activity_scores/archr_scores_peak_based", X_name = "scores")



# sce <- SingleCellExperiment(list(p2g_mat = p2g_mat))
# 
# writeH5AD(sce, "/omics/groups/OE0533/internal/katharina/scDoRI/gastrulation_data/jupyter_notebooks/p2g_gene_activity_scores/p2g_mat_250kb",
#           X_name = "p2g_mat")

# 
# 
# sce <- SingleCellExperiment(list(peak_mat = peak_mat))
# 
# writeH5AD(sce, "/omics/groups/OE0533/internal/katharina/scDoRI/gastrulation_data/jupyter_notebooks/p2g_gene_activity_scores/peak_mat",
#           X_name = "peak_mat")


# cp_names <- colnames(colData(gene_expr))
# cp_names[20] <- "celltypes"
# colnames(colData(gene_expr)) <- cp_names

sce <- SingleCellExperiment(list(genes = expr_mat),
                           #rowData = as.data.frame(rownames(gene_expr)),
                           colData = as.data.frame(colData(gene_expr)))

# writeH5AD(sce, "/omics/groups/OE0533/internal/katharina/scDoRI/gastrulation_data/jupyter_notebooks/p2g_gene_activity_scores/gene_expr_mat",
#           X_name = "genes")
# 
# 
# #p2g_mat_norm <- p2g_mat / rowSums(p2g_mat)
# scores <- p2g_mat %*% peak_mat
# scores <- t(t(scores) / colSums(scores))
# stopifnot(any(is.na(scores)) == FALSE)
# scores@x <- pmin(1e9, exp(scores@x) - 1)
# 
# 
# 
# sce <- SingleCellExperiment(list(investigation = investigation))
# 
# writeH5AD(sce, "/omics/groups/OE0533/internal/katharina/scDoRI/gastrulation_data/jupyter_notebooks/p2g_gene_activity_scores/investigation_scores",
#           X_name = "investigation")





# latent embedding
emb <- getReducedDims(
  ArchRProj = proj,
  reducedDims = "atac_LSI_100000",
  returnMatrix = TRUE,
  dimsToUse = 1:30,
  scaleDims = NULL,
  corCutOff = 0.75
)
dim(emb)


sce <- SingleCellExperiment(list(embedding = emb))

writeH5AD(sce, "/omics/groups/OE0533/internal/katharina/scDoRI/gastrulation_data/jupyter_notebooks/p2g_gene_activity_scores/archr_lsi_embedding",
          X_name = "embedding")

Granja JM, Pierce SE, Corces MR. 2021. ArchR Is a Scalable Software Package for Integrative Single-Cell Chromatin Accessibility Analysis. Nat Genet. Vols. 53(3):403-411. doi: 10.1038/s41588-021-00790-6.

Persad, Sitara, Zi-Ning Choo, Christine Dien, Ignas Masilionis, Ronan Chaligné, Tal Nawy, Chrysothemis C Brown, Itsik Pe’er, Manu Setty, and Dana Pe’er. 2022. “SEACells: Inference of Transcriptional and Epigenomic Cellular States from Single-Cell Genomics Data.” bioRxiv. Cold Spring Harbor Laboratory. https://doi.org/10.1101/2022.04.02.486748.

Zuin J., Zhan Y., Roth G. 2022. “Nonlinear Control of Transcription Through Enhancer-Promoter Interactions.” Nature. https://doi.org/10.1038/s41586-022-04570-y.

LS0tCnRpdGxlOiAiSW52ZXN0aWdhdGluZyBwMmdfbWF0IgpiaWJsaW9ncmFwaHk6IHJlZmVyZW5jZXMuYmliCm91dHB1dDogCiAgaHRtbF9kb2N1bWVudDoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2RlcHRoOiAyCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogICAgdGhlbWU6IGNvc21vCiAgICBoaWdobGlnaHQ6IHRleHRtYXRlCi0tLQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGNhY2hlID0gRkFMU0UpCmtuaXRyOjpvcHRzX2tuaXQkc2V0KHJvb3QuZGlyID0gIi9vbWljcy9ncm91cHMvT0UwNTMzL2ludGVybmFsL2thdGhhcmluYS9zY0RvUkkvZ2FzdHJ1bGF0aW9uX2RhdGFfbmV3IikKc2V0d2QoIi9vbWljcy9ncm91cHMvT0UwNTMzL2ludGVybmFsL2thdGhhcmluYS9zY0RvUkkvZ2FzdHJ1bGF0aW9uX2RhdGFfbmV3IikKc2V0LnNlZWQoMSkKYGBgCgpgYGB7cn0Kc3VwcHJlc3NQYWNrYWdlU3RhcnR1cE1lc3NhZ2VzKHsKCmxpYnJhcnkoQXJjaFIpCmxpYnJhcnkocGFyYWxsZWwpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KFNpbmdsZUNlbGxFeHBlcmltZW50KQpsaWJyYXJ5KHplbGxrb252ZXJ0ZXIpCmxpYnJhcnkoZHR3Y2x1c3QpCn0pCmBgYAoKYGBge3J9CgojIyMgVkFSSUFCTEVTCgpwcm9qX25hbWUgPC0gIi9vbWljcy9ncm91cHMvT0UwNTMzL2ludGVybmFsL2thdGhhcmluYS9zY0RvUkkvZ2FzdHJ1bGF0aW9uX2RhdGFfbmV3L0thdGhpLzA3X2dlbmVfYWNpdGl2aXR5X3Njb3Jlcy8iCnAyZ19saW5rc19maWxlIDwtICIvb21pY3MvZ3JvdXBzL09FMDUzMy9pbnRlcm5hbC9rYXRoYXJpbmEvc2NEb1JJL2dhc3RydWxhdGlvbl9kYXRhX25ldy9LYXRoaS9wMmdfbGlua3MiCgojIGxvY2F0aW9uIG9mIHNldXJhdCBmaWxlCnNldXJhdF9maWxlIDwtICIvb21pY3MvZ3JvdXBzL09FMDUzMy9pbnRlcm5hbC9rYXRoYXJpbmEvc2NEb1JJL2dhc3RydWxhdGlvbl9kYXRhX25ldy9LYXRoaS9ybmFfc2V1cmF0IgoKc2VhY2VsbF9jc3ZfZmlsZSA8LSAiL29taWNzL2dyb3Vwcy9PRTA1MzMvaW50ZXJuYWwva2F0aGFyaW5hL3NjRG9SSS9nYXN0cnVsYXRpb25fZGF0YV9uZXcvS2F0aGkvcGVydHVyYmF0aW9uX3NlYV9kZl9uZXciCiMgd2hpY2ggR2VuZVNjb3JlTWF0cml4IHRvIHVzZSwgbmVlZHMgdG8gYmUgaW4gZ2V0QXZhaWxhYmxlTWF0cmljZXMocHJvaikKR2VuZVNjb3JlTWF0cml4IDwtICJHZW5lU2NvcmVNYXRyaXhfZ2VuZUJvZHkiCmBgYAoKCmBgYHtyfQpwcm9qIDwtIGxvYWRBcmNoUlByb2plY3QocHJval9uYW1lLCBzaG93TG9nbyA9IEZBTFNFKQoKcDJnIDwtIGdldFBlYWsyR2VuZUxpbmtzKAogIEFyY2hSUHJvaiA9IHByb2osCiAgY29yQ3V0T2ZmID0gLTEsCiAgcmVzb2x1dGlvbiA9IDEsCiAgRkRSQ3V0T2ZmID0gMWUtMDQsCiAgdmFyQ3V0T2ZmQVRBQyA9IC4yNSwKICB2YXJDdXRPZmZSTkEgPSAuMjUsIAogIHJldHVybkxvb3BzID0gRkFMU0UKKQpgYGAKCmBgYHtyfQpwZWFrcyA8LSBnZXRNYXRyaXhGcm9tUHJvamVjdChwcm9qLCB1c2VNYXRyaXggPSAiUGVha01hdHJpeCIsIGJpbmFyaXplID0gRkFMU0UpCgoKUEVBS19NQVQgPC0gYXNzYXlzKHBlYWtzKVtbMV1dCgojIHJlYWQgaW4gZ25lIGV4cHJlc3NzaW9uIG1hdHJpeApnZW5lX2V4cHIgPC0gZ2V0TWF0cml4RnJvbVByb2plY3QocHJvaiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1c2VNYXRyaXggPSAiR2VuZUV4cHJlc3Npb25NYXRyaXgiKQoKRVhQUl9NQVQgPC0gYXNzYXlzKGdlbmVfZXhwcilbWzFdXQpyb3duYW1lcyhFWFBSX01BVCkgPC0gcm93RGF0YShnZW5lX2V4cHIpJG5hbWUKCiMgcmVhZCBpbiBhcmNociBnZW5lIGFjdGl2aXR5IHNjb3JlcwphcmNocl9zY29yZXMgPC0gZ2V0TWF0cml4RnJvbVByb2plY3QocHJvaiwgdXNlTWF0cml4ID0gIkdlbmVTY29yZU1hdHJpeF9nZW5lQm9keSIpCgoKIyBjcF9uYW1lcyA8LSBjb2xuYW1lcyhjb2xEYXRhKGFyY2hyX3Njb3JlcykpCiMgY3BfbmFtZXNbMjBdIDwtICJjZWxsdHlwZXMiCiMgY29sbmFtZXMoY29sRGF0YShhcmNocl9zY29yZXMpKSA8LSBjcF9uYW1lcwoKYXJjaHJfc2NvcmVzX21hdCA8LSBhc3NheXMoYXJjaHJfc2NvcmVzKVtbMV1dCnJvd25hbWVzKGFyY2hyX3Njb3Jlc19tYXQpIDwtIHJvd0RhdGEoYXJjaHJfc2NvcmVzKSRuYW1lCgoKaHZnX2xpc3QgPC0gcmVhZFJEUygiS2F0aGkvaHZnLnJkcyIpCgoKbWV0YV9ybmEgPC0gcm93RGF0YShnZW5lX2V4cHIpICU+JSBhcy5kYXRhLmZyYW1lKCkgJT4lIG11dGF0ZShyb3dfaW5kZXggPSBzZXEobnJvdyguKSkpCmlkeCA8LSAobWV0YV9ybmEgJT4lIGZpbHRlcihuYW1lICVpbiUgaHZnX2xpc3QpKSRyb3dfaW5kZXgKCmV4cHJfc3ViIDwtIEVYUFJfTUFUW2lkeCwgXQoKCnNlYWNlbGxzIDwtIHJlYWQuY3N2KHNlYWNlbGxfY3N2X2ZpbGUpCgoKCmxpbmtzIDwtIHAyZyAlPiUgYXMuZGF0YS5mcmFtZSgpICU+JSAKICBmaWx0ZXIoQ29ycmVsYXRpb24gPiAwLjIpICU+JSAKICBmaWx0ZXIoaWR4Uk5BICVpbiUgaWR4KSAKCnN0b3BpZm5vdChhbGwobGlua3MkQ29ycmVsYXRpb24gPiAwKSkKCgpwMmdfbWF0IDwtIHNwYXJzZU1hdHJpeChpID0gbGlua3MkaWR4Uk5BLAogICAgICAgICAgICAgaiA9IGxpbmtzJGlkeEFUQUMsCiAgICAgICAgICAgICB4PSBsaW5rcyRDb3JyZWxhdGlvbiwgCiAgICAgICAgICAgICBkaW1zID0gYyhkaW0oRVhQUl9NQVQpWzFdLAogICAgICAgICAgICAgZGltKFBFQUtfTUFUKVsxXSkpCgpyb3duYW1lcyhwMmdfbWF0KSA8LSByb3dEYXRhKGdlbmVfZXhwcikkbmFtZQoKCnJvd25hbWVzKFBFQUtfTUFUKSA8LSBzZXEuaW50KGRpbShQRUFLX01BVClbMV0pCmNvbG5hbWVzKHAyZ19tYXQpIDwtIHNlcS5pbnQoZGltKFBFQUtfTUFUKVsxXSkKCgoKIyByZW1vdmUgY29sdW1ucyBvZiBwZWFrcyB3aGljaCBhcmUgbm90IGxpbmtlZCB0byBhbnkgcGVhawpwMmdfbWF0X3N1YiA8LSBwMmdfbWF0WywgY29sU3VtcyhwMmdfbWF0KSAhPSAwXQojIHVzZSBvbmx5IGhpZ2hseSB2YXJpYWJsZSBnZW5lcwpwMmdfbWF0X3N1YiA8LSBwMmdfbWF0X3N1YltodmdfbGlzdCwgXQojIHJlbW92ZSBhbnkgZ2VuZXMgd2hpY2ggYXJlIG5vdCBsaW5rZWQgdG8gYW55IHBlYWsKcDJnX21hdF9zdWIgPC0gcDJnX21hdF9zdWJbcm93U3VtcyhwMmdfbWF0X3N1YikgIT0gMCwgXQpzdG9waWZub3QoYWxsKHJvd25hbWVzKHAyZ19tYXRfc3ViKSAlaW4lIGh2Z19saXN0KSkKc3RvcGlmbm90KGFueShpcy5uYShwMmdfbWF0X3N1YikgPT0gRkFMU0UpKQoKIyBrZWVwIG9ubHkgcGVha3Mgd2hpY2ggYXJlIGxpbmtlZCB0byBnZW5lcyBpbiB0aGUgYWNjZXNzaWJpbGl0eSBtYXRyaXgKcGVha19tYXRfc3ViIDwtIFBFQUtfTUFUW2NvbG5hbWVzKHAyZ19tYXRfc3ViKSwgXQpzdG9waWZub3Qocm93bmFtZXMocGVha19tYXRfc3ViKSA9PSBjb2xuYW1lcyhwMmdfbWF0X3N1YikpCiNzdG9waWZub3QoYW55KGlzLm5hKHBlYWtfbWF0X3N1YikgPT0gRkFMU0UpKQpzdG9waWZub3QoZGltKHBlYWtfbWF0X3N1YilbMV0gPT0gZGltKHAyZ19tYXRfc3ViKVsyXSkKCmV4cHJfbWF0X3N1YiA8LSBFWFBSX01BVFthcy52ZWN0b3Iocm93bmFtZXMocDJnX21hdF9zdWIpKSwgXQpgYGAKCgpgYGB7cn0KR0VORV9BTk5PIDwtIHJvd0RhdGEoZ2VuZV9leHByKQpnZW5lX2NvbERhdGEgPC0gY29sRGF0YShnZW5lX2V4cHIpICU+JSBhcy5kYXRhLmZyYW1lKCkKZ2VuZV9jb2xEYXRhIDwtIGRwbHlyOjpyZW5hbWUoZ2VuZV9jb2xEYXRhLCBjZWxsdHlwZXMgPSBjZWxsdHlwZS5tYXBwZWQpCgoKYXJjaHJfY29sRGF0YSA8LSBjb2xEYXRhKGFyY2hyX3Njb3JlcykgJT4lIGFzLmRhdGEuZnJhbWUoKQphcmNocl9jb2xEYXRhIDwtIGRwbHlyOjpyZW5hbWUoYXJjaHJfY29sRGF0YSwgY2VsbHR5cGVzID0gY2VsbHR5cGUubWFwcGVkICkKCiNhcmNocl9zY29yZXNfbWF0IDwtIGFyY2hyX3Njb3Jlc19tYXRbLCAxOjEwMDBdCmFyY2hyX2NvbERhdGEgPC0gYXJjaHJfY29sRGF0YSAlPiUgcm93bmFtZXNfdG9fY29sdW1uKCJjZWxsIikgJT4lCiAgZHBseXI6OmZpbHRlcihjZWxsICVpbiUgY29sbmFtZXMoYXJjaHJfc2NvcmVzX21hdCkpICU+JQogIGNvbHVtbl90b19yb3duYW1lcygiY2VsbCIpCgphcmNocl9zY29yZXNfc3ViIDwtIGFyY2hyX3Njb3Jlc19tYXRbYXMudmVjdG9yKHJvd25hbWVzKGV4cHJfbWF0X3N1YikpLCBzZWFjZWxscyRpbmRleF0KCmBgYAoKCiMgUDJHLWxpbmsgbWF0cml4IAoKSW4gb3JkZXIgdG8gZ2V0IGdlbmUgcmVndWxhdG9yeSBsaW5rcywgb25lIGNhbiBjb21wdXRlIGEgc2ltcGxlIGNvcnJlbGF0aW9uCmJldHdlZW4gYWNjZXNzaWJsZSBwZWFrcyBhbmQgZ2VuZSBleHByZXNzaW9uLCBpbiBvcmRlciB0byBmaW5kIHBlYWtzIHdob3NlIGFjdGl2aXR5CmlzIGhpZ2hseSBjb3JyZWxhdGVkIHdpdGggZXhwcmVzc2lvbiBvZiBhIGNlcnRhaW4gZ2VuZS4gVGhlc2UgYXJlIHBvdGVudGlhbCAKZW5oYW5jZXJzIG9mIGEgZ2VuZS4gU2luY2Ugc2luZ2xlIGNlbGwgZGF0YSBpcyB2ZXJ5IHNwYXJzZSwgdGhlIGNvbW1vbiB3YXkgdG8gCmNvbXB1dGUgY29ycmVsYXRpb3NuIGlzIGJ5IGFnZ3JlZ2F0aW5nIGFjY2Vzc2liaWxpdHkgYW5kIGdlbmUgZXhwcmVzc2lvbiBkYXRhCmFjcm9zcyBjZWxsIGFnZ3JlZ2F0ZXMuIEluIEFyY2hSIHRoaXMgaXMgZG9uZSBieSBzYW1wbGluZyA1MDAgY2VsbHMgZnJvbSB0aGUgCmVudGlyZSBkYXRhc2V0IGFuZCBmaW5kaW5nIHRoZSA1MCBuZWFyZXN0IG5laWdoYm9ycyBvZiB0aGVzZSBjZWxscy4gVGhlc2UgY2VsbAphZ2dyZWdhdGVzIHRoZXJlZm9yZSByZXByc2VudCBncm91cHMgb2Ygc2ltaWxhciBjZWxscyBhbmQgY2FuIGJlIHVzZWQgdG8gY29tcHV0ZQpjb3JyZWxhdGlvbnMuIAoKTm90YWJseSwgZm9yIGNvbXB1dGluZyBsaW5rcyB3aXRoaW4gYSBjZXJ0YWluIGRpc3RhbmNlIG9uIHRoZSBjaHJvbW9zb21lLCBBcmNoUgpkb2VzIG5vdCB0YWtlIGludG8gY29uc2lkZXJhdGlvbiB0aGUgc3RyYW5kIG9yaWVudGF0aW9uLCBidXQgY29tcHV0ZXMgdGhlIApkaXN0YW5jZSBiZXR3ZWVuIHRoZSAic3RhcnQiIGNvb3JkaW5hdGUgYW5kIHRoZSBwZWFrIG1pZGRsZSBjb29yZGluYXRlLiBIb3dldmVyLApvbiB0aGUgbWludXMgc3RyYW5kIHRoZSBUU1MgaXMgdGhlICJlbmQiIGNvb3JkaW5hdGUuIEZvciB0aGUgY29ycmVsYXRpb25zIHRoaXMKaXMgbm90IGltcG9ydGFudCwgYnV0IGluIG15IGNvbXB1dGF0aW9ucyBJIHdpbGwgdXNlIHRoZSBUU1MgY29vcmRpbmF0ZSBpbgphIHN0cmFuZC1hd2FyZSBmYXNoaW9uLgoKCkJhc2VkIG9uIHRoZXNlIHB1dGF0aXZlIHBlYWstdG8tZ2VuZSBsaW5rcywgaXQgaXMgcG9zc2libGUgdG8gY29tcHV0ZSBnZW5lIGFjdGl2aXR5CnNjb3Jlcy4gSWYgdGhlc2Ugc2NvcmVzIHJlY2FwaXR1bGF0ZSBnZW5lIGV4cHJlc3Npb24gd2VsbCwgdGhpcyBpcyBhIAp2YWxpZGF0aW9uIG9mIHRoZSBsaW5rcy4gTmV2ZXJ0aGVsZXNzLCBpdCBpcyBleHBlY3RlZCB0aGF0IGdlbmUgYWN0aXZpdHkgc2NvcmVzCmNvcnJlbGF0ZSBoaWdobHkgd2l0aCBnZW5lIGV4cHJlc3Npb24sIHNpbmNlIHRoZSBwZWFrcyB1c2VkIGZvciB0aGUgY29tcHV0YXRpb24gCmFyZSBoaWdobHkgY29ycmVsYXRlZCB3aXRoIHRoZSBnZW5lcyBwZXIgZGVmaW5pdGlvbi4gSW4gdGhlIGZvbGxvd2luZyB5b3Ugd2lsbCBmaW5kIGEgZnVuY3Rpb24gdG8gY29tcHV0ZSBnZW5lIGFjdGl2aXR5IHNjb3JlcyBmcm9tIHBlYWstdG8tZ2VuZSBsaW5rcywgYWRwYXRlZCBmcm9tIApDaWNlcm8sIHdoZXJlIGdlbmUgYWN0aXZpdCBzY29yZXMgYXJlIGNvbXB1dGVkIGZyb20gY28tYWNjZXNzaWJsZSBwZWFrcy4KCkZ1cnRoZXJtb3JlLCBzaW5jZSBwZWFrcyB3aGljaCBhcmUgZmFydGhlciBhd2F5IGZyb20gYSBnZW5lIG9uIHRoZSBnZW5vbWUgYXJlIGxlc3MgbGlrZWx5IAp0byByZWd1bGF0ZSB0aGlzIGdlbmUsIGl0IGlzIGNvbW1vbiB0byB1c2UgZGlzdGFuY2Ugd2VpZ3RocyB0byBwZW5hbGl6ZSBwZWFrcyB3aGljaAphcmUgaGlnaGx5IGNvcnJlbGF0ZWQsIGJ1dCBkaXN0YW50LiBIb3dldmVyLCBJIG9ic2VydmVkIHRoYXQgdXNpbmcgZGlzdGFuY2Ugd2VpZ3RocwpkZWNyZWFzZXMgdGhlIGNvcnJlbGF0aW9uIHdpdGggZ2VuZSBleHByZXNzaW9uLCB3aXRoIGxlc3Mgc3RlZXAgZGVjYXkgcmF0ZXMgCnJlc3VsdGluZyBpbiBiZXR0ZXIgZ2VuZSBhY3Rpdml0eSBzY29yZXMuIFRoaXMgc2hvd3MgdGhhdCB0aGUgZGlzdGFuY2Ugd2VpZ2h0cyAKbGVhZCB0byBhIGxvdCBvZiB6ZXJvIHZhbHVlcyB3aGVuIG11bHRpcGxpZWQgd2l0aCB0aGUgY29ycmVsYXRpb24gdmFsdWVzLiBTdGlsbCwKYmlvbG9naWNhbGx5IHZlcnkgZGlzdGFudCBwZWFrcyBhcmUgcHJvYmFibHkgbm90IGNvcnJlbGF0ZWQgd2l0aCBhIHByb21vdGVyLCBiZWNhdXNlIAp0aGV5IGFyZSBpbnRlcmVhY3RpbmcsIGJ1dCBtb3JlIGxpa2VseSwgYXJlIGFyYml0cmFyeSBjb3JyZWxhdGlvbnMuIEZpbmRpbmcgYSAKZ29vZCB0cmFkZS1vZmYgYmV0d2VlbiBjb25zaWRlcmluZyBjb3JyZWxhdGlvbnMgYWNyb3NzIGxhcmdlIGRpc3RhbmNlcywgYnV0IGFsc28KdXNpbmcgcHJpb3Iga25vd2xlZGdlIGFib3V0IHRoZSBiaW9sb2d5IGFuZCByZXN0cmljdGluZyB0aGUgbGlua3MgdG8gYSBjZXJ0YWluIAp3aW5kb3cgaXMgbm9uLXRyaXZpYWwuIFRoZSBjb3JyZWN0IGRpc3RhbmNlIGRlY2F5IHJhdGUgIHByb2JhYmx5IGRlcGVuZHMgb24gZWFjaCBpbmRpdmlkdWFsIGdlbmUgYW5kIG1pZ2h0IGRpZmZlciBhY3Jvc3MgY2VsbHR5cGVzLgoKWWV0IGFub3RoZXIgYXBwcm9hY2ggd291bGQgYmUgdG8gdXNlIG9ubHkgcGVha3MsIHdoaWNoIGFyZSB3aXRoaW4gKy8tIDEwMGtiIG9mIHRoZQpUU1Mgb2YgYSBnZW5lLCB0aGVyZWJ5LCByZW1vdmluZyBhbnkgcGVha3Mgd2hpY2ggYXJlIGZhciBhd2F5LiBUaGlzIGlzIHNpbWlsYXIgdG8gCnRoZSBhcHByb2FjaCBpbiBBcmNoUi4gSGVyZSwgdGhlIGdlbmUgYWN0aXZpdHkgc2NvcmVzIGZvciBlYWNoIGdlbmUgYXJlIGNvbXB1dGVkCmJhc2VkIG9uIGFsbCBwZWFrcyB3aGljaCBhcmUgd2l0aGluICsvLSAxMDBicCBvZiB0aGUgVFNTIG9mIHRoZSBnZW5lLiBBcyB5b3UgCndpbGwgc2VlIGluIHRoZSBmb2xsb3dpbmcgcGxvdHMgdXNpbmcgdGhpcyBhcHByb2FjaCBsZWFkcyB0byB2ZXJ5IGhpZ2ggY29ycmVsYXRpb25zCmJldHdlZW4gZ2VuZSBleHByZXNzaW9uIGFuZCBnZW5lIGFjdGl2aXR5IHNjb3Jlcy4gQ29tcHV0aW5nIHRoZSBzY29yZXMgYmFzZWQgb24gCnBlYWstdG8tZ2VuZSBsaW5rcyBvZmZlcnMgb25seSBhIG1pbm9yIGltcHJvdmVtZW50LiAKClRoZSBtYWluIHB1cnBvc2Ugb2YgdGhlIGVudGlyZSBleGNlcmNpc2Ugd2FzIHRvIGJlIGFibGUgdG8gY29tcGFyZSB0aGUgZ29vZG5lc3MgCm9mIHRoZXNlIGxpbmtzIHRvIGxpbmtzIG9idGFpbmVkIHVzaW5nIHNjRG9SaS4gVGhpcyByZWxhdGlvbnNoaXAgd2lsbCBoYXZlIHRvIGJlIApleHBsb3JlZCBmdXJ0aGVyLiAKCgpgYGAje3J9CnAyZyA8LSByZWFkUkRTKHAyZ19saW5rc19maWxlKQpgYGAKClJlYWQgaW4gdGhlIHBlYWsgYWNjZXNzaWJpbGl0eSBtYXRyaXggYW5kIHRoZSBnZW5lIGV4cHJlc3Npb24gbWF0cml4OgoKYGBgI3tyfQojIGdldCBwZWFrIG1hdHJpeApwZWFrcyA8LSBnZXRNYXRyaXhGcm9tUHJvamVjdChwcm9qLCB1c2VNYXRyaXggPSAiUGVha01hdHJpeCIsIGJpbmFyaXplID0gRkFMU0UpClBFQUtfTUFUIDwtIGFzc2F5cyhwZWFrcylbWzFdXQoKI3NhdmVSRFMocGVha3MsICJLYXRoaS9wZWFrc19hcmNociIpCiNzYXZlUkRTKFBFQUtfTUFULCAiS2F0aGkvcGVha19tYXRfYXJjaHIiKQoKIyByZWFkIGluIGduZSBleHByZXNzc2lvbiBtYXRyaXgKZ2VuZV9leHByIDwtIGdldE1hdHJpeEZyb21Qcm9qZWN0KHByb2osIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdXNlTWF0cml4ID0gIkdlbmVFeHByZXNzaW9uTWF0cml4IikKRVhQUl9NQVQgPC0gYXNzYXlzKGdlbmVfZXhwcilbWzFdXQpyb3duYW1lcyhFWFBSX01BVCkgPC0gcm93RGF0YShnZW5lX2V4cHIpJG5hbWUKR0VORV9BTk5PIDwtIHJvd0RhdGEoZ2VuZV9leHByKQpnZW5lX2NvbERhdGEgPC0gY29sRGF0YShnZW5lX2V4cHIpCiNzYXZlUkRTKGdlbmVfZXhwciwgImdlbmVfZXhwcl9hcmNoci5yZHMiKQoKIyByZWFkIGluIGFyY2hyIGdlbmUgYWN0aXZpdHkgc2NvcmVzCmFyY2hyX3Njb3JlcyA8LSBnZXRNYXRyaXhGcm9tUHJvamVjdChwcm9qLCB1c2VNYXRyaXggPSBHZW5lU2NvcmVNYXRyaXgpCiNzYXZlUkRTKGFyY2hyX3Njb3JlcywgImdlbmVfYWN0aXZpdHlfc2NvcmVzX2dlbmVfYm9keS5yZHMiKQoKIyBjaGFuZ2UgY2VsbHR5cGUgY29sdW1uIG5hbWUKY3BfbmFtZXMgPC0gY29sbmFtZXMoY29sRGF0YShhcmNocl9zY29yZXMpKQpjcF9uYW1lc1syMF0gPC0gImNlbGx0eXBlcyIKY29sbmFtZXMoY29sRGF0YShhcmNocl9zY29yZXMpKSA8LSBjcF9uYW1lcwoKIyBleHRyYWN0IGdlbmUgYWN0aXZpdHkgc2NvcmVzIGZyb20gQXJjaFIKYXJjaHJfc2NvcmVzX21hdCA8LSBhc3NheXMoYXJjaHJfc2NvcmVzKVtbMV1dCnJvd25hbWVzKGFyY2hyX3Njb3Jlc19tYXQpIDwtIHJvd0RhdGEoYXJjaHJfc2NvcmVzKSRuYW1lCiMgZ2V0IG1ldGFkYXRhIG9mIGdlbmUgYWN0aXZpdHkgc2NvcmVzCmFyY2hyX2NvbERhdGEgPC0gY29sRGF0YShhcmNocl9zY29yZXMpCgpybShwZWFrcykKcm0oZ2VuZV9leHByKQpybShhcmNocl9zY29yZXMpCmdjKHJlc2V0ID0gVFJVRSkKYGBgCgoKQ0hFQ0sgSUYgVEhFIFdIT0xFIFRISU5HIFJVTlMgV0lUSE9VVCBSRU1PVklORyBOQU5zCgpgYGAje3J9CgoKUEVBS19NQVQgPC0gcmVhZFJEUygiS2F0aGkvcGVha19tYXRfYXJjaHIiKQojUEVBS19NQVQgPC0gUEVBS19NQVRbLCAxOjEwMDBdCgpnZW5lX2V4cHIgPC0gcmVhZFJEUygiS2F0aGkvZ2VuZV9leHByX2FyY2hyLnJkcyIpCkVYUFJfTUFUIDwtIGFzc2F5cyhnZW5lX2V4cHIpW1sxXV0Kcm93bmFtZXMoRVhQUl9NQVQpIDwtIHJvd0RhdGEoZ2VuZV9leHByKSRuYW1lCkdFTkVfQU5OTyA8LSByb3dEYXRhKGdlbmVfZXhwcikKZ2VuZV9jb2xEYXRhIDwtIGNvbERhdGEoZ2VuZV9leHByKSAlPiUgYXMuZGF0YS5mcmFtZSgpCmdlbmVfY29sRGF0YSA8LSBkcGx5cjo6cmVuYW1lKGdlbmVfY29sRGF0YSwgY2VsbHR5cGVzID0gY2VsbHR5cGUubWFwcGVkKQoKI0VYUFJfTUFUIDwtIEVYUFJfTUFUWywgMToxMDAwXQoKYGBgCgoKSXQgaXMgaW1wb3J0YW50IGZvciB0aGUgZnVuY3Rpb25zIGJlbG93IHRoYXQgdGhlIGNvbHVtbiB3aGljaCBjb250YWlucyB0aGUgY2VsbHR5cGVzIAppcyBjYWxsZWQgImNlbGx0eXBlcyIuIEhlcmUgd2UgcmVuYW1lIHRoZSBjb2x1bW4gZnJvbSAiY2VsbHR5cGUubWFwcGVkIiB0byAiY2VsbHR5cGVzIi4KCmBgYCN7cn0KCmFyY2hyX3Njb3JlcyA8LSByZWFkUkRTKCJLYXRoaS9nZW5lX2FjdGl2aXR5X3Njb3Jlc19nZW5lX2JvZHkucmRzIikKI3NhdmVSRFMoYXJjaHJfc2NvcmVzLCAiZ2VuZV9hY3Rpdml0eV9zY29yZXNfZ2VuZV9ib2R5LnJkcyIpCgojIGNoYW5nZSBjZWxsdHlwZSBjb2x1bW4gbmFtZQojIGNwX25hbWVzIDwtIGNvbG5hbWVzKGNvbERhdGEoYXJjaHJfc2NvcmVzKSkKIyBjcF9uYW1lc1tjZWxsdHlwZS5tYXBwZWRdIDwtICJjZWxsdHlwZXMiCiMgY29sbmFtZXMoY29sRGF0YShhcmNocl9zY29yZXMpKSA8LSBjcF9uYW1lcwoKIyBleHRyYWN0IGdlbmUgYWN0aXZpdHkgc2NvcmVzIGZyb20gQXJjaFIKYXJjaHJfc2NvcmVzX21hdCA8LSBhc3NheXMoYXJjaHJfc2NvcmVzKVtbMV1dCnJvd25hbWVzKGFyY2hyX3Njb3Jlc19tYXQpIDwtIHJvd0RhdGEoYXJjaHJfc2NvcmVzKSRuYW1lCiMgZ2V0IG1ldGFkYXRhIG9mIGdlbmUgYWN0aXZpdHkgc2NvcmVzCmFyY2hyX2NvbERhdGEgPC0gY29sRGF0YShhcmNocl9zY29yZXMpICU+JSBhcy5kYXRhLmZyYW1lKCkKYXJjaHJfY29sRGF0YSA8LSBkcGx5cjo6cmVuYW1lKGFyY2hyX2NvbERhdGEsIGNlbGx0eXBlcyA9IGNlbGx0eXBlLm1hcHBlZCApCgojYXJjaHJfc2NvcmVzX21hdCA8LSBhcmNocl9zY29yZXNfbWF0WywgMToxMDAwXQphcmNocl9jb2xEYXRhIDwtIGFyY2hyX2NvbERhdGEgJT4lIHJvd25hbWVzX3RvX2NvbHVtbigiY2VsbCIpICU+JQogIGRwbHlyOjpmaWx0ZXIoY2VsbCAlaW4lIGNvbG5hbWVzKGFyY2hyX3Njb3Jlc19tYXQpKSAlPiUKICBjb2x1bW5fdG9fcm93bmFtZXMoImNlbGwiKQoKcm0oYXJjaHJfc2NvcmVzKQpybShnZW5lX2V4cHIpCmdjKHJlc2V0ID0gVFJVRSkKYGBgCgoKCgpXZSB3aWxsIG9ubHkgdXNlIHBlYWtzIGxpbmtlZCB0byBoaWdobHkgdmFyaWFibGUgZ2VuZXMgdG8gY29tcHV0ZSBnZW5lCmFjdGl2aXR5IHNjb3Jlcy4KCmBgYCN7cn0KIyByZWFkIGluIGxpc3Qgb2YgaGlnaGx5IHZhcmlhYmxlIGdlbmVzCmh2Z19saXN0IDwtIHJlYWRSRFMoIkthdGhpL2h2Zy5yZHMiKQoKIyBnZXQgUk5BIGluZGV4IG9mIGh2ZwptZXRhX3JuYSA8LSBHRU5FX0FOTk8gJT4lIGFzLmRhdGEuZnJhbWUoKSAlPiUgbXV0YXRlKHJvd19pbmRleCA9IHNlcShucm93KC4pKSkKaWR4IDwtIChtZXRhX3JuYSAlPiUgZHBseXI6OmZpbHRlcihuYW1lICVpbiUgaHZnX2xpc3QpKSRyb3dfaW5kZXgKCmV4cHJfc3ViIDwtIEVYUFJfTUFUW2lkeCwgXQpgYGAKCmBgYCN7cn0Kc2VhY2VsbHMgPC0gcmVhZC5jc3Yoc2VhY2VsbF9jc3ZfZmlsZSkKCnNlYWNlbGxzIDwtIHNlYWNlbGxzICU+JSBkcGx5cjo6ZmlsdGVyKGluZGV4ICVpbiUgY29sbmFtZXMoRVhQUl9NQVQpKQoKI3NlYWNlbGxzIDwtIGRyb3BfbmEoc2VhY2VsbHMpCmBgYAoKCmBgYCN7cn0KbGlua3MgPC0gcDJnICU+JSBhcy5kYXRhLmZyYW1lKCkgJT4lIAogIGRwbHlyOjpmaWx0ZXIoQ29ycmVsYXRpb24gPiAwLjIpICU+JSAKICBkcGx5cjo6ZmlsdGVyKGlkeFJOQSAlaW4lIGlkeCkgCgpzdG9waWZub3QoYWxsKGxpbmtzJENvcnJlbGF0aW9uID4gMCkpCmBgYAoKCgpDcmVhdGUgYSBwMmcgbGluayBtYXRyaXgKCmBgYCN7cn0KcDJnX21hdCA8LSBzcGFyc2VNYXRyaXgoaSA9IGxpbmtzJGlkeFJOQSwKICAgICAgICAgICAgIGogPSBsaW5rcyRpZHhBVEFDLAogICAgICAgICAgICAgeD0gbGlua3MkQ29ycmVsYXRpb24sIAogICAgICAgICAgICAgZGltcyA9IGMoZGltKEVYUFJfTUFUKVsxXSwKICAgICAgICAgICAgIGRpbShQRUFLX01BVClbMV0pKQoKcm93bmFtZXMocDJnX21hdCkgPC0gR0VORV9BTk5PJG5hbWUKCgpyb3duYW1lcyhQRUFLX01BVCkgPC0gc2VxLmludChkaW0oUEVBS19NQVQpWzFdKQpjb2xuYW1lcyhwMmdfbWF0KSA8LSBzZXEuaW50KGRpbShQRUFLX01BVClbMV0pCmBgYAoKCgpGaWx0ZXIgYW5kIHByZXBhcmUgcGVhayBtYXRyaXggYW5kIHAyZyBsaW5rcyBtYXRyaXg6CgpgYGAje3J9CiMgcmVtb3ZlIGNvbHVtbnMgb2YgcGVha3Mgd2hpY2ggYXJlIG5vdCBsaW5rZWQgdG8gYW55IHBlYWsKcDJnX21hdF9zdWIgPC0gcDJnX21hdFssIGNvbFN1bXMocDJnX21hdCkgIT0gMF0KIyB1c2Ugb25seSBoaWdobHkgdmFyaWFibGUgZ2VuZXMKcDJnX21hdF9zdWIgPC0gcDJnX21hdF9zdWJbaHZnX2xpc3QsIF0KIyByZW1vdmUgYW55IGdlbmVzIHdoaWNoIGFyZSBub3QgbGlua2VkIHRvIGFueSBwZWFrCnAyZ19tYXRfc3ViIDwtIHAyZ19tYXRfc3ViW3Jvd1N1bXMocDJnX21hdF9zdWIpICE9IDAsIF0Kc3RvcGlmbm90KGFsbChyb3duYW1lcyhwMmdfbWF0X3N1YikgJWluJSBodmdfbGlzdCkpCnN0b3BpZm5vdChhbnkoaXMubmEocDJnX21hdF9zdWIpID09IEZBTFNFKSkKCiMga2VlcCBvbmx5IHBlYWtzIHdoaWNoIGFyZSBsaW5rZWQgdG8gZ2VuZXMgaW4gdGhlIGFjY2Vzc2liaWxpdHkgbWF0cml4CnBlYWtfbWF0X3N1YiA8LSBQRUFLX01BVFtjb2xuYW1lcyhwMmdfbWF0X3N1YiksIHNlYWNlbGxzJGluZGV4XQpzdG9waWZub3Qocm93bmFtZXMocGVha19tYXRfc3ViKSA9PSBjb2xuYW1lcyhwMmdfbWF0X3N1YikpCiNzdG9waWZub3QoYW55KGlzLm5hKHBlYWtfbWF0X3N1YikgPT0gRkFMU0UpKQpzdG9waWZub3QoZGltKHBlYWtfbWF0X3N1YilbMV0gPT0gZGltKHAyZ19tYXRfc3ViKVsyXSkKCmV4cHJfbWF0X3N1YiA8LSBFWFBSX01BVFthcy52ZWN0b3Iocm93bmFtZXMocDJnX21hdF9zdWIpKSwgc2VhY2VsbHMkaW5kZXhdCgpnZW5lX2NvbERhdGEgPC0gZ2VuZV9jb2xEYXRhICU+JSByb3duYW1lc190b19jb2x1bW4oImNlbGwiKSAlPiUKICBkcGx5cjo6ZmlsdGVyKGNlbGwgJWluJSBjb2xuYW1lcyhleHByX21hdF9zdWIpKSAlPiUKICBjb2x1bW5fdG9fcm93bmFtZXMoImNlbGwiKQoKYXJjaHJfc2NvcmVzX3N1YiA8LSBhcmNocl9zY29yZXNfbWF0W2FzLnZlY3Rvcihyb3duYW1lcyhleHByX21hdF9zdWIpKSwgc2VhY2VsbHMkaW5kZXhdCgoKYGBgCgoKCgoKCiMjIyBGdW5jdGlvbiB0byBjb21wdXRlIGdlbmUgYWN0aXZpdHkgc2NvcmVzCgpgYGB7cn0KZ2VuZV9hY3Rpdml0eV9zY29yZXMgPC0gZnVuY3Rpb24ocGVha19tYXQsIHAyZ19tYXQpIHsKICAjcGVha19tYXRfc3Vic2V0IDwtIHBlYWtfbWF0W2NvbG5hbWVzKHAyZ19tYXQpLCBdCiAgIyBub3JtYWxpemUgdGhlIHAyZyBtYXRyaXggYnkgdGhlIHRvdGFsIG51bWJlciBvZiBwZWFrcyBsaW5rZWQgdG8gZWFjaCBnZW5lCiAgcDJnX21hdCA8LSBwMmdfbWF0IC8gcm93U3VtcyhwMmdfbWF0KQogIHByaW50KHBhc3RlMCgibm9ybWFsaXplZCB0aGUgcDJnIG1hdHJpeCIpKQogIHN0b3BpZm5vdChhbnkoaXMubmEocDJnX21hdCkpID09IEZBTFNFKQogICMgTm93IHdlIGNhbiBjb21wdXRlIGEgd2VpZ2h0ZWQgc3VtIG9mIHBlYWsyZ2VuZSBjb3JyZWxhdGlvbnMgZm9yIGVhY2gKICAjIHBlYWsgYW5kIGdlbmUKICBzY29yZXMgPC0gcDJnX21hdCAlKiUgcGVha19tYXQKICBwcmludChwYXN0ZTAoIkNvbXB1dGVkIHdlaWdodGVzIHN1bSBvZiBwZWFrcyBmb3IgZWFjaCBnZW5lIGFuZCBjZWxsIikpCiAgIyBjcmVhdGUgYSBkYXRhZnJhbWUgZm9yIGNvbXB1dGluZyB0aGUgbGluZWFyIG1vZGVsCiAgbGluZWFyX21vZGVsX2RmIDwtIGRhdGEuZnJhbWUoY2VsbCA9IGNvbG5hbWVzKHNjb3JlcyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0b3RhbF9hY3Rpdml0eSA9IGNvbFN1bXMoc2NvcmVzKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvdGFsX3NpdGVzID0gY29sU3VtcyhwZWFrX21hdCkpCiAgIyBjb21wdXRlIGEgbGluZWFyIG1vZGVsCiAgYWN0aXZpdHlfbW9kZWwgPC0gc3RhdHM6OmxtKGxvZyh0b3RhbF9hY3Rpdml0eSkgfiBsb2codG90YWxfc2l0ZXMpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IGxpbmVhcl9tb2RlbF9kZikKICAjIGV4dHJhY3QgdGhlIGZpdHRlZCBtb2RlbAogIGxpbmVhcl9tb2RlbF9kZiRmaXR0ZWRfY3VydmUgPC0gZXhwKGFzLnZlY3RvcihwcmVkaWN0KGFjdGl2aXR5X21vZGVsLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlID0gInJlc3BvbnNlIikpKQogICMgY29tcHV0ZSBzaXplIGZhY3RvcnMgZnJvbSBmaXR0ZWQgbW9kZWwKICBzaXplX2ZhY3RvcnMgPC0gbWVhbihsaW5lYXJfbW9kZWxfZGYkZml0dGVkX2N1cnZlKSAvIGxpbmVhcl9tb2RlbF9kZiRmaXR0ZWRfY3VydmUKICAjIGNyZWF0ZSBkaWFnb25hbCBtYXRyaXggY29udGFpbmluZyB0aGUgc2l6ZSBmYWN0b3JzCiAgc2l6ZV9mYWN0b3JzX21hdCA8LSBNYXRyaXg6OkRpYWdvbmFsKHggPSBzaXplX2ZhY3RvcnMpCiAgI3Jvdy5uYW1lcyhzaXplX2ZhY3RvcnNfbWF0KSA8LSBsaW5lYXJfbW9kZWxfZGYkY2VsbAogICMgbm9ybWFsaXplIGJ5IGxpYnJhcnkgZGVwdGggc2l6ZSBmYWN0b3JzCiAgbm9ybV9zY29yZXMgPC0gTWF0cml4Ojp0KHNpemVfZmFjdG9yc19tYXQgJSolIE1hdHJpeDo6dChzY29yZXMpKQogIHByaW50KHBhc3RlMCgiTm9ybWFsaXplZCBmb3IgbGlicmFyeSBzaXplIikpCiAgIyBleHBvbmVudGlhdGUsIGJlY2F1c2UgUk5BIGNvdW50cyBhcmUgbG9nLW5vcm1hbGx5IGRpc3RyaWJ1dGVkCiAgbm9ybV9zY29yZXNAeCA8LSBwbWluKDFlOSwgZXhwKG5vcm1fc2NvcmVzQHgpIC0gMSkKICBwcmludChwYXN0ZTAoIkV4cG9uZW50aWF0ZWQgbWF0cml4IikpCiAgCiAgIyBmcmVlIHNvbWUgbWVtb3J5CiAgI3JtKHBlYWtfbWF0X3N1YnNldCkKICBybShhY3Rpdml0eV9tb2RlbCkKICBybShzY29yZXMpCiAgZ2MocmVzZXQgPSBUUlVFKQoKICAjIHNjYWxlIHdpdGggdG90YWwgYWN0aXZpdHkgc2NvcmVzIGFnYWluCiAgc2NhbGVfZmFjdG9ycyA8LSBNYXRyaXg6OkRpYWdvbmFsKHggPSAxL01hdHJpeDo6Y29sU3Vtcyhub3JtX3Njb3JlcykpCiAgcHJpbnQocGFzdGUwKCJEaXZpZGVkIGJ5IHRvdGFsIGFjdGl2aXR5IHRvIGdldCB2YWx1ZSBiZXR3ZWVuIHplcm8gYW5kIG9uZSIpKQogIAogIGZpbmFsX3Njb3JlcyA8LSBNYXRyaXg6OnQoc2NhbGVfZmFjdG9ycyAlKiUgTWF0cml4Ojp0KG5vcm1fc2NvcmVzKSkKCiAgcmV0dXJuKGZpbmFsX3Njb3JlcykKCn0KCmBgYAoKYGBge3J9CnAyZ19zY29yZXMgPC0gZ2VuZV9hY3Rpdml0eV9zY29yZXMocGVha19tYXRfc3ViLCBwMmdfbWF0X3N1YikKc2F2ZVJEUyhwMmdfc2NvcmVzLCAiS2F0aGkvQXJjaFJfcDJnX2Jhc2VkX2dlbmVfYWN0aXZpdHlfc2NvcmVzLnJkcyIpCmBgYAoKCgpUT0RPOiBBZGQgZnVuY3Rpb25zIGhlcmUsIGFkZCBBcmNoUiBhZ2dyZWdhdGVzIGFuZCBjb21wdXRlIGNvcnJlbGF0aW9ucyBhcyAKc2NhdHRlciAmIGRlbnNpdHkgcGxvdHMKCgoKCiMgRnVuY3Rpb25zCgoKCiMjIyBGdW5jdGlvbiB0byBjcmVhdGUgYWdncmVnYXRlIG1hdHJpY2VzOgoKYGBge3J9CiMgdGhlIGRhdGEgbWF0cml4IG5lZWRzIHRvIGJlIG9mIGRpbWVuc2lvbiBmZWF0dXJlcyB4IGNlbGxzCiMgbWV0YWRhdGEgb2YgZGF0YSBtYXRyaXggd2hpY2ggY29udGFpbnMgY2VsbHR5cGVzCiMgbmVlZHMgdG8gYmUgY2FsbGVkICJjZWxsdHlwZXMiCmNyZWF0ZV9jZWxsdHlwZV9hZ2dyZWdhdGVzIDwtIGZ1bmN0aW9uKG1ldGFkYXRhLCBkYXRhX21hdHJpeCwgY2VsbHR5cGVzKSB7CiAgI2NyZWF0ZSBlbXB0eSBtYXRyaXggdG8gc3RvcmUgYWdncmVnYXRlcwogIGFnZyA8LSBtYXRyaXgoZGF0YSA9IDAsCiAgICAgICAgICAgICAgICBucm93ID0gbnJvdyhkYXRhX21hdHJpeCksCiAgICAgICAgICAgICAgICBuY29sID0gbGVuZ3RoKGNlbGx0eXBlcyksCiAgICAgICAgICAgICAgICBkaW1uYW1lcyA9IGxpc3Qocm93bmFtZXMoZGF0YV9tYXRyaXgpLCBjZWxsdHlwZXMpKQogIAoKICBmb3IgKGNlbGx0eXBlIGluIGNlbGx0eXBlcykgewogICAgYmFyY29kZXMgPC0gcm93bmFtZXMobWV0YWRhdGEgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGFzLmRhdGEuZnJhbWUoKSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgZHBseXI6OmZpbHRlcihjZWxsdHlwZXMgPT0gY2VsbHR5cGUpKQogICAgaWYgKGxlbmd0aChiYXJjb2RlcykgPT0gMSl7CiAgICAgICAgYWdnWywgY2VsbHR5cGVdIDwtIGRhdGFfbWF0cml4WywgYmFyY29kZXNdCiAgICAgICAgcHJpbnQocGFzdGUwKCJXYXJuaW5nISBDZWxsdHlwZSIsIGNlbGx0eXBlLCAiY29udGFpbnMgb25seSBvbmUgY2VsbC4iKSkKICAgIH0gZWxzZXsKICAgICAgYWdnWywgY2VsbHR5cGVdIDwtIHJvd1N1bXMoZGF0YV9tYXRyaXhbLCBiYXJjb2Rlc10pCiAgICB9CiAgfQogIHN0b3BpZm5vdChhbnkoaXMubmEoYWdnKSkgPT0gRkFMU0UpCiAgcmV0dXJuKGFnZykKfQoKCmNyZWF0ZV9jZWxsdHlwZV9hZ2dyZWdhdGVzX3AyZ19zY29yZXMgPC0gZnVuY3Rpb24oZ2VuZV9leHByX21ldGFkYXRhLCBwMmdfc2NvcmVfbWF0cml4LCBjZWxsdHlwZXMpIHsKICAgICNjcmVhdGUgZW1wdHkgbWF0cml4IHRvIHN0b3JlIGFnZ3JlZ2F0ZXMKICBhZ2cgPC0gbWF0cml4KGRhdGEgPSAwLAogICAgICAgICAgICAgICAgbnJvdyA9IG5yb3cocDJnX3Njb3JlX21hdHJpeCksCiAgICAgICAgICAgICAgICBuY29sID0gbGVuZ3RoKGNlbGx0eXBlcyksCiAgICAgICAgICAgICAgICBkaW1uYW1lcyA9IGxpc3Qocm93bmFtZXMocDJnX3Njb3JlX21hdHJpeCksIGNlbGx0eXBlcykpCiAgCgogIGZvciAoY2VsbHR5cGUgaW4gY2VsbHR5cGVzKSB7CiAgICBiYXJjb2RlcyA8LSByb3duYW1lcyhnZW5lX2V4cHJfbWV0YWRhdGEgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGFzLmRhdGEuZnJhbWUoKSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgZHBseXI6OmZpbHRlcihjZWxsdHlwZXMgPT0gY2VsbHR5cGUpKQogICAgaWYgKGxlbmd0aChiYXJjb2RlcykgPT0gMSkgewogICAgICBhZ2dbLCBjZWxsdHlwZXNdIDwtIHAyZ19zY29yZV9tYXRyaXhbLCBiYXJjb2Rlc10KICAgICAgcHJpbnQocGFzdGUwKCJXYXJuaW5nISBDZWxsdHlwZSIsIGNlbGx0eXBlLCAiY29udGFpbnMgb25seSBvbmUgY2VsbC4iKSkKICAgIH0gZWxzZSB7CiAgICAgIGFnZ1ssIGNlbGx0eXBlXSA8LSByb3dTdW1zKHAyZ19zY29yZV9tYXRyaXhbLCBiYXJjb2Rlc10pCiAgICB9CiAgfQogIHN0b3BpZm5vdChhbnkoaXMubmEoYWdnKSkgPT0gRkFMU0UpCiAgcmV0dXJuKGFnZykKfQoKCmNyZWF0ZV9zZWFjZWxsX2FnZ3JlZ2F0ZXMgPC0gZnVuY3Rpb24oZGF0YV9tYXRyaXgsIHNlYWNlbGxzX2RmKXsKICBhZ2cgPC0gbWF0cml4KGRhdGEgPSAwLAogICAgICAgICAgICAgICAgbnJvdyA9IG5yb3coZGF0YV9tYXRyaXgpLAogICAgICAgICAgICAgICAgbmNvbCA9IGxlbmd0aCh1bmlxdWUoc2VhY2VsbHNfZGYkU0VBQ2VsbCkpLAogICAgICAgICAgICAgICAgZGltbmFtZXMgPSBsaXN0KHJvd25hbWVzKGRhdGFfbWF0cml4KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdW5pcXVlKHNlYWNlbGxzX2RmJFNFQUNlbGwpKSkKICAjc3RvcGlmbm90KG5yb3coYWdnKSA9PSBucm93KGRhdGFfbWF0cml4KSkKICBmb3IgKHNlYWNlbGwgaW4gdW5pcXVlKHNlYWNlbGxzX2RmJFNFQUNlbGwpKXsKICAgICNwcmludChzZWFjZWxsKQogICAgYmFyY29kZXMgPC0gKHNlYWNlbGxzX2RmICU+JSBkcGx5cjo6ZmlsdGVyKFNFQUNlbGwgPT0gc2VhY2VsbCkpJGluZGV4CiAgICAjcHJpbnQoYmFyY29kZXMpCiAgICBpZiAobGVuZ3RoKGJhcmNvZGVzKSA9PSAxKXsKICAgICAgYWdnWywgc2VhY2VsbF0gPC0gZGF0YV9tYXRyaXhbLCBiYXJjb2Rlc10KICAgICAgcHJpbnQocGFzdGUwKCJXYXJuaW5nISBTRUFDZWxsIiwgc2VhY2VsbCwgImNvbnRhaW5zIG9ubHkgb25lIGNlbGwuIikpCiAgICB9IGVsc2V7CiAgICAgIGFnZ1ssIHNlYWNlbGxdIDwtIHJvd1N1bXMoZGF0YV9tYXRyaXhbLCBiYXJjb2Rlc10pCiAgICB9CiAgfQogIHN0b3BpZm5vdChhbnkoaXMubmEoYWdnKSkgPT0gRkFMU0UpCiAgcmV0dXJuKGFnZykKfQoKYGBgCgoKIyMjIEZ1bmN0aW9uIHRvIGNvbXB1dGUgcm93LXdpc2UgY29ycmVsYXRpb25zIGJldHdlZW4gdHdvIG1hdHJpY2VzOgoKYGBge3J9ClJPV19DT1JSX1RIRU1FIDwtICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLAogICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTUpLCAjIGNoYW5nZSBzaXplIG9mIGF4aXMgdGl0bGUKICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE1KSwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBzaXplID0gMjApLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJOb25lIiwgCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAiZ3JleSIpLCAgICMgTWFqb3IgZ3JpZCBsaW5lcwogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ3aGl0ZSIsIGNvbG91ciA9ICJibGFjayIpLAogICAgICAgIGFzcGVjdC5yYXRpbyA9IDAuNCkgIAoKCgoKCnJvd3dpc2VfY29ycmVsYXRpb25zIDwtIGZ1bmN0aW9uKE1hdHJpeEEsIE1hdHJpeEIsIG5hbWUpIHsKICBpbnRlcnNlY3RfZ2VuZXMgPC0gaW50ZXJzZWN0KHJvd25hbWVzKE1hdHJpeEEpLCByb3duYW1lcyhNYXRyaXhCKSkKICBNYXRyaXhBIDwtIE1hdHJpeEFbaW50ZXJzZWN0X2dlbmVzLCBdCiAgTWF0cml4QiA8LSBNYXRyaXhCW2ludGVyc2VjdF9nZW5lcywgXQogIGNvcnJlbGF0aW9ucyA8LSBjKCkKICBmb3IgKGkgaW4gc2VxLmludChkaW0oTWF0cml4QSlbMV0pKSB7CiAgICByb3dBIDwtIE1hdHJpeEFbaSwgXQogICAgcm93QSA8LSByb3dBIC0gbWVhbihyb3dBKQogICAgaWYgKHNkKHJvd0EpICE9IDApIHsKICAgICAgcm93QSA8LSByb3dBIC8gc2Qocm93QSkKICAgIH0KICAKICAgIHJvd0IgPC0gTWF0cml4QltpLCBdCiAgICByb3dCIDwtIHJvd0IgLSBtZWFuKHJvd0IpCiAgICBpZiAoc2Qocm93QikgIT0gMCl7CiAgICAgIHJvd0IgPC0gcm93QiAvIHNkKHJvd0IpCiAgICB9CiAgICAKICAgIGNvcnJfdmFsdWUgPC0gbWVhbihyb3dBICogcm93QikKICAgIGNvcnJlbGF0aW9ucyA8LSBjKGNvcnJlbGF0aW9ucywgY29ycl92YWx1ZSkKICB9CiAgbmFtZXMoY29ycmVsYXRpb25zKSA8LSByb3duYW1lcyhNYXRyaXhBKQogIHBsb3QgPC0gZ2dwbG90KCkgKyBnZW9tX2hpc3RvZ3JhbShhZXMoeCA9IGNvcnJlbGF0aW9ucyksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiaW5zID0gMjAwLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbD0iIzY5YjNhMiIpICsgbGFicyh0aXRsZSA9IHBhc3RlMChuYW1lKSkgKwogICAgUk9XX0NPUlJfVEhFTUUKICAgIAogIHJldHVybihsaXN0KGNvcnJlbGF0aW9ucywgcGxvdCkpCn0KYGBgCgojIyMgUGxvdCBUaGVtZXMKClBsb3QgVGhlbWUgZm9yIGNvbXBhcmluZyBjb3JyZWxhdGlvbnMuCgpgYGB7cn0KQ09SUl9USEVNRSA8LSAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwKICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE1KSwgIyBjaGFuZ2Ugc2l6ZSBvZiBheGlzIHRpdGxlCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSksCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgc2l6ZSA9IDIwKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAiTm9uZSIsIAogICAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2xpbmUoY29sb3VyID0gImdyZXkiKSwgICAjIE1ham9yIGdyaWQgbGluZXMKICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAid2hpdGUiLCBjb2xvdXIgPSAiYmxhY2siKSwKICAgICAgICBhc3BlY3QucmF0aW8gPSAxKSAgCmBgYAoKUGxvdCB0aGVtZSBmb3IgcGxvdHMgd2hpY2ggYXJlIG1jdWggd2lkZXIgdGhhbiBoaWdoLgoKYGBge3J9ClRIRU1FX0xPTkcgPC0gICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLAogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSksICMgY2hhbmdlIHNpemUgb2YgYXhpcyB0aXRsZQogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTUpLAogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIHNpemUgPSAyMCksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIk5vbmUiLCAKICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9saW5lKGNvbG91ciA9ICJncmV5IiksICAgIyBNYWpvciBncmlkIGxpbmVzCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIndoaXRlIiwgY29sb3VyID0gImJsYWNrIiksCiAgICAgICAgYXNwZWN0LnJhdGlvID0gMC4yKQpgYGAKClBsb3QgdGhlbWUgZm9yIHN0YW5kYXJkIHBsb3RzIChzbGlnaGx5IHdpZGVyIHRoYW4gaGlnaCkuCgpgYGB7cn0KQ1VTVE9NX1RIRU1FIDwtICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjUsIGhqdXN0PTEsIHNpemUgPSAxMiksCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwKICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIwKSwgIyBjaGFuZ2Ugc2l6ZSBvZiBheGlzIHRpdGxlCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAyMCksCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgc2l6ZSA9IDI1KSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAiTm9uZSIsIAogICAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2xpbmUoY29sb3VyID0gImdyZXkiKSwgICAjIE1ham9yIGdyaWQgbGluZXMKICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAid2hpdGUiLCBjb2xvdXIgPSAiYmxhY2siKSwKICAgICAgICBhc3BlY3QucmF0aW8gPSAwLjMpCmBgYAoKIyBDZWxsdHlwZSBhZ2dyZWdhdGVzCgojIyBBcmNoUiBnZW5lIGFjdGl2aXR5IHNjb3JlcwoKVG8gY29tcHV0ZSB0aGUgY29ycmVsYXRpb25zIGJldHdlZW4gZ2VuZSBleHByZXNzaW9uIGFuZCBBcmNoUiBnZW5lIGFjdGl2aXR5IApzY29yZXMgSSBmaXJzdCBhZ2dyZWdhdGVkIGNlbGxzIGFjY29yZGluZyB0byBjZWxsdHlwZXMgdG8gY29tcHV0ZSAKY29ycmVsYXRpb25zLiBBcyBjYW4gYmUgc2VlbiBpbiB0aGUgcGxvdCBiZWxvdywgdGhpcyB5aWVsZHMgdmVyeSBoaWdoIApjb3JyZWxhdGlvbiB2YWx1ZXMuIFRoaXMgaXMgYXMgZXhwZWN0ZWQsIHNpbmNlIGluIFtAR3JhbmphXSB0aGUgYXV0aG9ycyAKY29tcGFyZWQgNTIgZGlmZmVyZW50IHdheXMgb2YgY29tcHV0aW5nIGdlbmUgYWN0aXZpdHkgc2NvcmVzIGZyb20gQVRBQy1zZXEgCmRhdGEgYW5kIGZvdW5kIHRoZWlyIG1ldGhvZCB0byBiZSB0aGUgYmVzdCBvbmUuIAoKCmBgYHtyLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9Nn0KCm5hbWUgPC0gIkFyY2hSX3Njb3JlcywgQ2VsbHR5cGUgYWdncmVnYXRlcyIKCmFyY2hyX3Njb3Jlc19hZ2cgPC0gY3JlYXRlX2NlbGx0eXBlX2FnZ3JlZ2F0ZXMoYXJjaHJfY29sRGF0YSwgYXJjaHJfc2NvcmVzX3N1YiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1bmlxdWUoYXJjaHJfY29sRGF0YSRjZWxsdHlwZXMpKQoKZXhwcl9hZ2dfY2VsbHR5cGVzIDwtIGNyZWF0ZV9jZWxsdHlwZV9hZ2dyZWdhdGVzKGdlbmVfY29sRGF0YSwgZXhwcl9tYXRfc3ViLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVuaXF1ZShnZW5lX2NvbERhdGEkY2VsbHR5cGVzKSkKCnAyZ19hZ2dfY2VsbHR5cGVzIDwtIGNyZWF0ZV9jZWxsdHlwZV9hZ2dyZWdhdGVzX3AyZ19zY29yZXMoZ2VuZV9jb2xEYXRhLCBwMmdfc2NvcmVzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVuaXF1ZShnZW5lX2NvbERhdGEkY2VsbHR5cGVzKSkKCmFyY2hyX2NvcnJzIDwtIHJvd3dpc2VfY29ycmVsYXRpb25zKGV4cHJfYWdnX2NlbGx0eXBlcywgYXJjaHJfc2NvcmVzX2FnZywgIkNvcnJlbGF0aW9uIGdlbmUgZXhwci4gJiBBcmNoUiBnZW5lIGFjdGl2aXR5IHNjb3JlcyIpCnAyZ19jb3JycyA8LSByb3d3aXNlX2NvcnJlbGF0aW9ucyhleHByX2FnZ19jZWxsdHlwZXMsIHAyZ19hZ2dfY2VsbHR5cGVzLCAiQ29ycmVsYXRpb24gZ2VuZSBleHByLiAmIHAyZyBhY3Rpdml0eSBzY29yZXMiKQoKY293cGxvdDo6cGxvdF9ncmlkKGFyY2hyX2NvcnJzW1syXV0sIHAyZ19jb3Jyc1tbMl1dLCBuY29sID0gMSkKCmdnc2F2ZSgiS2F0aGkvcGxvdHMvQ29ycmVsYXRpb25zX2NlbGxfYWdncmVnYXRlcy5wZGYiKQpgYGAKCmBgYHtyLCBmaWcud2lkdGg9NiwgZmlnLmhlaWdodD02fQpnZ3Bsb3QoKSArICNnZW9tX2RlbnNpdHkyZF9maWxsZWQoYWVzKHggPSBjb3JyZWxhdGlvbnNfMjUwa2IsIHkgPSBjb3Jyc1sxXSkpICMrCiAgZ2VvbV9wb2ludChhZXMoeSA9IGFyY2hyX2NvcnJzW1sxXV0sIHggPSBwMmdfY29ycnNbWzFdXSkpICsKICBnZW9tX2RlbnNpdHlfMmRfZmlsbGVkKGFlcyh5ID0gYXJjaHJfY29ycnNbWzFdXSwgeCA9IHAyZ19jb3Jyc1tbMV1dKSwgYWxwaGEgPSAwLjUpICsKICBnZW9tX2xpbmUoYWVzKHggPSAgYXJjaHJfY29ycnNbWzFdXSwgIGFyY2hyX2NvcnJzW1sxXV0pLCBjb2xvciA9ICJyZWQiKSArCiAgbGFicyh5ID0gIkNvcnJlbGF0aW9uIGdlbmUgZXhwci4gJiBwMmcgYWN0aXZpdHkgc2NvcmVzIiwKICAgICAgIHggPSAiQ29ycmVsYXRpb24gZ2VuZSBleHByLiAmIEFyY2hSIGdlbmUgYWN0aXZpdHkgc2NvcmVzIiwKICAgICAgIHRpdGxlID0gIkNlbGx0eXBlIGFnZ3JlZ2F0ZXMiKSArCiAgQ09SUl9USEVNRQoKZ2dzYXZlKCJLYXRoaS9wbG90cy9jb21wYXJpbmdfYXJjaHJfYWxsX3AyZ19saW5rcy5wZGYiKQpgYGAKCgoKIyBTRUFDZWxsIGFnZ3JlZ2F0ZXMKCkluc3RlYWQgb2YgdXNpbmcgY2VsbHR5cGUgYWdncmVnYXRlcyBhcyBhYm92ZSwgYW5vdGhlciBvcHRpb24gaXMgdG8KdXNlIFNFQUNlbGxzIGFzIGRlc2NyaWJlZCBpbiBbQFBlcnNhZDIwMjJdLiBUaGVzZSB3ZXJlIGNvbXB1dGVkIHVzaW5nClB5dGhvbiBhbmQgdGhlIHJlc3VsdGluZyBjZWxsIGFnZ3JlZ2F0ZXMgKCJtZXRhY2VsbHMiKSBhcmUgdXNlZCBmb3IKYWdncmVnYXRpbmcgZ2VuZSBleHByZXNzaW9uIGFuZCBnZW5lIGFjdGl2aXR5IHNjb3JlcyBiZWxvdy4gVGhlIGNvcnJlbGF0aW9ucwp3aGVuIHVzaW5nIFNFQUNlbGxzIGFyZSBtdWNoIGhpZ2hlciB0aGFuIHRoZSBjb3JyZWxhdGlvbnMgb2J0YWluZWQgdXNpbmcgCnRoZSBBcmNoUiBjZWxsIGFnZ3JlZ2F0ZXMuIEZvciB0aGlzIHJlYXNvbiBJIHdpbGwgdXNlIFNFQUNlbGxzIGZvciBjb21wdXRpbmcKY29ycmVsYXRpb25zIGluIHRoZSBmb2xsb3dpbmcgc3RlcHMuIAoKYGBge3IsIGZpZy53aWR0aCA9IDYgLCBmaWcuaGVpZ2h0PTZ9CgoKI3NlYWNlbGxzIDwtIHNlYWNlbGxzICU+JSBkcGx5cjo6ZmlsdGVyKGluZGV4ICVpbiUgY29sbmFtZXMoRVhQUl9NQVQpKQoKc3RvcGlmbm90KG5yb3cocDJnX3Njb3JlcykgPT0gbnJvdyhleHByX21hdF9zdWIpKQoKc2VhY2VsbF9wMmdfYWdnIDwtIGNyZWF0ZV9zZWFjZWxsX2FnZ3JlZ2F0ZXMocDJnX3Njb3Jlcywgc2VhY2VsbHMpCnNlYWNlbGxfcm5hX2FnZyAgPC0gY3JlYXRlX3NlYWNlbGxfYWdncmVnYXRlcyhleHByX21hdF9zdWIsIHNlYWNlbGxzKQpzZWFjZWxsX2FyY2hyX2FnZyA8LSBjcmVhdGVfc2VhY2VsbF9hZ2dyZWdhdGVzKGFyY2hyX3Njb3Jlc19zdWIsIHNlYWNlbGxzKQoKCnNlYWNlbGxfY29ycl9wMmcgPC0gcm93d2lzZV9jb3JyZWxhdGlvbnMoc2VhY2VsbF9ybmFfYWdnICwgc2VhY2VsbF9wMmdfYWdnLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUDJnIGxpbmtzIG9mIGVudGlyZSBjaHJvbW9zb21lLCBTRUFjZWxscyIgKQoKc2VhY2VsbF9jb3JyX2FyY2hyIDwtIHJvd3dpc2VfY29ycmVsYXRpb25zKHNlYWNlbGxfcm5hX2FnZywgc2VhY2VsbF9hcmNocl9hZ2csIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkFyY2hSIGdlbmUgYWN0aXZpdHkgc2NvcmVzLCBTRUFjZWxscyIpCgpjb3dwbG90OjpwbG90X2dyaWQoc2VhY2VsbF9jb3JyX3AyZ1tbMl1dICwgc2VhY2VsbF9jb3JyX2FyY2hyW1syXV0sIG5jb2wgPSAxKQoKYGBgCmBgYHtyLCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD02fQpnZ3Bsb3QoKSArICNnZW9tX2RlbnNpdHkyZF9maWxsZWQoYWVzKHggPSBjb3JyZWxhdGlvbnNfMjUwa2IsIHkgPSBjb3Jyc1sxXSkpICMrCiAgZ2VvbV9wb2ludChhZXMoeCA9IHNlYWNlbGxfY29ycl9wMmdbWzFdXSwgeSA9IHNlYWNlbGxfY29ycl9hcmNocltbMV1dKSkgKwogIGdlb21fZGVuc2l0eV8yZF9maWxsZWQoYWVzKHggPSBzZWFjZWxsX2NvcnJfcDJnW1sxXV0sIHkgPSBzZWFjZWxsX2NvcnJfYXJjaHJbWzFdXSksIGFscGhhID0gMC41KSArCiAgZ2VvbV9saW5lKGFlcyh4ID0gc2VhY2VsbF9jb3JyX2FyY2hyW1sxXV0sIHkgPSBzZWFjZWxsX2NvcnJfYXJjaHJbWzFdXSksIGNvbG9yID0gInJlZCIgKSAgKwogIGxhYnMoeCA9ICJDb3JyZWxhdGlvbiBnZW5lIGV4cHIuICYgYWxsIHAyZyBhY3Rpdml0eSBzY29yZXMiLAogICAgICAgeSA9ICJDb3JyZWxhdGlvbiBnZW5lIGV4cHIuICYgQXJjaFIgZ2VuZSBhY3Rpdml0eSBzY29yZXMiLAogICAgICAgdGl0bGUgPSAiU0VBQ2VsbHMsIGFsbCBwMmcgbGlua3MiKSArCiAgQ09SUl9USEVNRSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIk5vbmUiKQoKZ2dzYXZlKCJLYXRoaS9wbG90cy9zZWFjZWxsX2FnZ3JlYWdhdGVzX3AyZ19hcmNoci5wZGYiKQoKYGBgCgoKCgojIERpc3RhbmNlIHdlaWdodHMKClVzaW5nIEFyY2hSIFtAR3JhbmphXSBJIGNvbXB1dGVkIHBlYWstdG8tZ2VuZSBsaW5rcyBhY3Jvc3MgdGhlIGVudGlyZSAKY2hyb21vc29tZSwgYnV0IG5vdCBiZXR3ZWVuIGNocm9tc29tZXMuIFRoaXMgbWVhbnMgdGhhdCBhIGxvdCBvZiAKY29ycmVsYXRpb25zIGFyZSBmb3VuZCBiZXR3ZWVuIHBlYWtzIHZlcnkgZmFyIGF3YXkgZnJvbSB0aGUgcHJvbW90ZXIvZ2VuZQp0aGV5IGFyZSBsaW5rZWQgdG8uIEV2ZW4gdGhvdWdoIHRoZXNlIGNvcnJlbGF0aW9ucyBjYW4gYmUgcXVpdGUgaGlnaCBhbmQgaW50ZXJhY3Rpb25zCmJldHdlZW4gZW5oYW5jZXJzIGFuZCBwcm9tb3RlcnMgY2FuIG9jY3VyIG92ZXIgbWVnYWJhc2UgZGlzdGFuY2VzLCBhIHJlYWwKYmlvbG9naWNhbCBpbnRlcmFjdGlvbiBiZWNvbWVzIGxlc3MgbGlrZWx5IHRoZSBsYXJnZXIgdGhlIGRpc3RhbmNlIGlzLiBUaGVyZWZvcmUsIHNpbmNlIHdlciBhcmUgaW50ZXJlc3RlZCBpbiBiaW9sb2dpY2FsbHkgcmVsZXZhbnQgYW5kIG5vdApzcHVyaW91cyBjb3JyZWxhdGlvbnMuIFRoZXJlZm9yZSwgYXMgc3VnZ2VzdGVkIGJ5IFtAR3JhbmphXSwgSSBhZGRlZCAKZGlzdGFuY2Ugd2VpZ2h0cywgc3VjaCB0aGF0IGZhcnRoZXIgYXdheSBwZWFrcyBsaW5rZWQgdG8gYSBnZW5lIGNvbnRyaWJ1dGUKbGVzcyB0byB0aGUgZ2VuZSBhY3Rpdml0eSBzY29yZSBvZiB0aGlzIHBhcnRpY3VsYXIgZ2VuZS4gCgpIZXJlLCBJIHVzZWQgYSBkaXN0YW5jZSBkZWNheSBmcm9tIHRoZSBUU1MsIGNvbXB1dGVkIGFzIGZvbGxvd3M6Cgokd2VpZ2h0ID0gZV57LShhYnMoZGlzdFRTUy9jKSl9JCB3aXRoICRjJCBiZWluZyBhIGNvbnN0YW50IGRldGVybWluaW5nIHRoZSBleHBvbmVudGlhbApkZWNheSByYXRlIG9mIHRoZSBkaXN0YW5jZSB3ZWlnaHRzLiBCZWxvdyBJIHRyaWVkIGRpZmZlcmVudCByYXRlcyB0byBiZXR0ZXIgdW5kZXJzdGFuZCAKd2hldGhlciB3ZSBjYW4gaW1wcm92ZSB0aGUgZ2VuZSBhY3Rpdml0eSBzY29yZXMgYnkgZ2l2aW5nIGEgaGlnaGVyIHdlaWdodCB0bwpjbG9zZSBwZWFrcyB0aGFuIHRvIGZhciBhd2F5IHBlYWtzLiBBcyBjYW4gYmUgc2VlbiBiZWxvdyB0aGlzIGRpZCBub3QgaW1wcm92ZSwgdGhlCnNjb3JlcywgYnV0IHJhdGhlciB0aGUgc2NvcmVzIGJlY2FtZSB3b3JzZSwgd2hpY2ggaXMgcHJvYmFibHkgZHVlIHRvIHRoZSBmYWN0IHRoYXQKbW9zdCBjb3JyZWxhdGlvbiB2YWx1ZXMgd2lsbCBnZXQgdmVyeSBzbWFsbCB3ZWlnaHRzIHRoaXMgd2F5IGFuZCBtb3N0IHBlYWtzIGxpbmtlZAp3aXRoIGEgZ2VuZSwgZXZlbiBpZiB0aGUgY29ycmVsYXRpb24gdmFsdWUgaXMgaGlnaCwgd2lsbCBub3QgY29udHJpYnV0ZSB0byB0aGUgZ2VuZQphY3Rpdml0eSBzY29yZSBhbnltb3JlLgoKKipDYXJlZnVsOiBUaGUgcDJnIGlua3MgaW4gQXJjaFIgYXJlIGNvbXB1dGVkIGZvciBwZWFrIGFuZCBnZW5lIHBhaXJzIHdoaWNoIGFyZSAKd2l0aGluIGEgY2VydGFpbiBkaXN0YW5jZSBmcm9tIGVhY2ggb3RoZXIuIEhvd2V2ZXIsIG5vdCB0aGUgcmVhbCBUU1Mgb2YgYSBnZW5lIGlzCnVzZWQgZm9yIHRoaXMsIGJ1dCByYXRlciB0aGUgZGlzdGFuY2UgYmV0d2VlbiBzdGFydCBjb29yZGluYXRlCm9mIGEgZ2VuZSBhbmQgcGVhayBzdGFydCBjb29yZGluYXRlLCBub3QgdGFraW5nIGludG8gY29uc2lkZXJhdGlvbiB0aGUgc3RyYW5kIGRpcmVjdGlvbmFsaXR5LgoKCgojIyMgRnVuY3Rpb24gdG8gY29tcHV0ZSBkaXN0YW5jZS13ZWlnaHRlZCBnZW5lIGFjdGl2aXR5IHNjb3JlcyBmcm9tIHAyZyBsaW5rcwoKYGBge3J9CiMgQXMgaW5wdXQgZm9yIHRoaXMgZnVuY3Rpb24gaXQgaXMgYmVzdCB0byB1c2Ugb25seSB0aGUgbW9zdCBoaWdobHkgdmFyaWFibGUgZ2VuZXMKZGlzdGFuY193ZWlnaHRlZF9nZW5lX2FjdGl2aXR5X3Njb3JlcyA8LSBmdW5jdGlvbihwMmdfbWF0X3N1YiwgZ2VuZU1vZGVsID0gImV4cCgtZGlzdGFuY2UvNTAwMCkiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3ZWlnaHQgPSA1MDAwMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwZWFrX21hdCwgbGlua3MsIHAyZ19vcmlnaW5hbCwgZ2VuZV9hbm5vKXsKICBhdGFjX2dyYW5nZXMgPC0gbWV0YWRhdGEocDJnX29yaWdpbmFsKVtbMV1dCiAgI3JuYV9ncmFuZ2VzIDwtIG1ldGFkYXRhKHAyZ19vcmlnaW5hbClbWzJdXQogIGdlbmVfYW5ub19vcmlnaW5hbCA8LSBnZW5lX2Fubm8KICAjIGNyZWF0ZSBnZW5lIGFubm90YXRpb25zIHdpdGggc3RhcnQgY29vcmRpbmF0ZSBvZiBlYWNoIGdlbmUKICAjIHN1YnNldCB0byBjb250YWluIG9ubHkgZ2VuZXMgd2hpY2ggYXJlIGluY2x1ZGVkIGluIG91ciBwZWFrMmdlbmUgbWF0cml4CiAgZ2VuZV9hbm5vIDwtIGdlbmVfYW5ubyAlPiUgYXMuZGF0YS5mcmFtZSgpICU+JQogICAgbXV0YXRlKGlkeFJOQSA9IHNlcShucm93KC4pKSkgJT4lIAogICAgZHBseXI6OmZpbHRlcihuYW1lICVpbiUgcm93bmFtZXMocDJnX21hdF9zdWIpKSAlPiUKICAgIG11dGF0ZShzdHJhbmQgPSBpZmVsc2Uoc3RyYW5kID09IDEsICIrIiwgIi0iKSkgJT4lIAogICAgbXV0YXRlKHN0YXJ0X2Nvb3JkID0gaWZlbHNlKHN0cmFuZCA9PSAiKyIsIHN0YXJ0LCBlbmQpKSAlPiUgCiAgICByZW5hbWUoZ2VuZSA9IG5hbWUpICMlPiUgR1JhbmdlcygpCgogICMgc3Vic2V0IGF0YWMgZ3JhbmdlcyAmIGdldCBtaWRkbGUgb2YgZWFjaCBwZWFrCiAgcG9zX2F0YWNfZ3JhbmdlcyA8LSBhdGFjX2dyYW5nZXMgICU+JSAKICAgIGFzLmRhdGEuZnJhbWUoKSAlPiUKICAgIG11dGF0ZShpZHhBVEFDID0gc2VxKG5yb3coLikpKSAlPiUgCiAgICAjIGdyb3VwX2J5KHNlcW5hbWVzKSAlPiUKICAgICMgbXV0YXRlKGlkeCA9IHNlcV9hbG9uZyhzZXFuYW1lcykpICU+JSAKICAgICMgdW5ncm91cCAlPiUKICAgICN0aWR5cjo6dW5pdGUoY2hyX2lkeCwgc2VxbmFtZXMsIGlkeCwgcmVtb3ZlID0gRkFMU0UsIHNlcCA9ICJfIikgJT4lIAogICAgZHBseXI6OmZpbHRlcihpZHhBVEFDICVpbiUgY29sbmFtZXMocDJnX21hdF9zdWIpKSAlPiUgCiAgICBtdXRhdGUobWlkZGxlID0gc3RhcnQgKyAzMDApICMlPiUgR1JhbmdlcygpIAogIAogICNUT0RPOiBGaWx0ZXIgZm9yIGdlbmVzIQogIHN0b3BpZm5vdChsZW5ndGgodW5pcXVlKGxpbmtzJGlkeEFUQUMpKSA9PSBkaW0ocG9zX2F0YWNfZ3JhbmdlcylbWzFdXSkKICBzdG9waWZub3QobGVuZ3RoKHVuaXF1ZShsaW5rcyRpZHhSTkEpKSA9PSBkaW0oZ2VuZV9hbm5vKVtbMV1dKQogICNwMmdfZmlsdCA8LSBwMmdfb3JpZ2luYWwgJT4lIGFzLmRhdGEuZnJhbWUoKSAlPiUgZmlsdGVyKGdlbmUgJWluJSByb3duYW1lcyhwMmdfbWF0KSkKICAKICAKICAjIGNvbWJpbmUgdGhlIHRocmVlIGRhdGFmcmFtZXMKICBwMmdfam9pbiA8LSBsZWZ0X2pvaW4obGlua3MsIGFzLmRhdGEuZnJhbWUocG9zX2F0YWNfZ3JhbmdlcyksCiAgICAgICAgICAgICAgICAgICAgICAgIGJ5ID0gImlkeEFUQUMiKQogIHAyZ19qb2luIDwtIGxlZnRfam9pbihwMmdfam9pbiwgYXMuZGF0YS5mcmFtZShnZW5lX2Fubm8pLAogICAgICAgICAgICAgICAgICAgICAgICBieSA9ICJpZHhSTkEiLCBzdWZmaXggPSBjKCIuYXRhYyIsICIucm5hIikpCgogICMgY29tcHV0ZSBkaXN0YW5jZSBhbmQgZGlzdGFuY2Ugd2VpZ2h0cyAKICBwMmdfam9pbiA8LSBwMmdfam9pbiAlPiUgCiAgICBtdXRhdGUoZGlzdGFuY2UgPSBhYnMoc3RhcnRfY29vcmQgLSBtaWRkbGUpKSAlPiUKICAgIG11dGF0ZShkaXN0YW5jZV93ZWlnaHQgPSBldmFsKHBhcnNlKHRleHQ9Z2VuZU1vZGVsKSkpCiAgCiAgCiAgIyBjcmVhdGUgZGlzdGFuY2Ugd2VpZ2h0IG1hdHJpeAogIHAyZ19kdyA8LSBzcGFyc2VNYXRyaXgoaSA9IHAyZ19qb2luJGlkeFJOQSwKICAgICAgICAgICAgICAgICAgICAgICAgIGogPSBwMmdfam9pbiRpZHhBVEFDLAogICAgICAgICAgICAgICAgICAgICAgICAgeCA9IHAyZ19qb2luJGRpc3RhbmNlX3dlaWdodCwKICAgICAgICAgICAgICAgICAgICAgICAgIGRpbXMgPSBjKG5yb3coZ2VuZV9hbm5vX29yaWdpbmFsKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5yb3cocGVha19tYXQpKSwKICAgICAgICAgICAgICAgICAgICAgICAgIGRpbW5hbWVzID0gbGlzdChnZW5lX2Fubm9fb3JpZ2luYWwkbmFtZSAsIAogICAgICAgICAgICAgICAgICAgICAgICAgc2VxLmludChucm93KHBlYWtfbWF0KSkpCiAgICAgICAgICAgICAgICAgICAgICAgICApCgoKICBwMmdfZHcgPC0gcDJnX2R3W2FzLnZlY3Rvcihyb3duYW1lcyhwMmdfbWF0X3N1YikpLCBjb2xuYW1lcyhwMmdfbWF0X3N1YildCiAgCiAgIyBlbGVtZW50d2lzZSBtYXRyaXggbXVsdGlwbGljYXRpb24KICB3ZWlnaHRlZF9wMmdfbWF0IDwtIHAyZ19tYXRfc3ViICogcDJnX2R3CiAgCiAgcHJpbnQocGFzdGUobGVuZ3RoKHdoaWNoKHJvd1N1bXMod2VpZ2h0ZWRfcDJnX21hdCkgPT0gMCkpLCAiZ2VuZXMgaGF2ZSBvbmx5IHplcm8gY29ycmVsYXRpb24gdmFsdWVzLCBzbyB3ZSB3aWxsIHJlbW92ZSB0aGVtLiIpKQogIHdlaWdodGVkX3AyZ19tYXQgPC0gd2VpZ2h0ZWRfcDJnX21hdFtyb3dTdW1zKHdlaWdodGVkX3AyZ19tYXQpICE9IDAsIF0KICBwcmludChwYXN0ZTAoIldlIGFyZSBsZWZ0IHdpdGggIiwgZGltKHdlaWdodGVkX3AyZ19tYXQpWzFdLCAiIGdlbmVzIikpCiAgCiAgIyBjb21wdXRlIGdlbmUgYWN0aXZpdHkgc2NvcmVzIGJhc2VkIG9uIGRpc3RhbmNlLXdlaWdodGVkIHBlYWsyZ2VuZSBtYXRyaXgKICB3ZWlnaHRlZF9zY29yZXMgPC0gZ2VuZV9hY3Rpdml0eV9zY29yZXMocGVha19tYXRfc3ViLCB3ZWlnaHRlZF9wMmdfbWF0KQogIAogIHJldHVybih3ZWlnaHRlZF9zY29yZXMpIAp9CmBgYAoKYGBge3J9CndlaWdodGVkX3Njb3JlcyA8LSBkaXN0YW5jX3dlaWdodGVkX2dlbmVfYWN0aXZpdHlfc2NvcmVzKHAyZ19tYXRfc3ViID0gcDJnX21hdF9zdWIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW5lTW9kZWwgPSAiZXhwKC1kaXN0YW5jZS81MDAwKSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdlaWdodCA9IDUwMDAwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBlYWtfbWF0ID0gUEVBS19NQVQsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpbmtzID0gbGlua3MsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHAyZ19vcmlnaW5hbCA9IHAyZywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VuZV9hbm5vID0gR0VORV9BTk5PKQpgYGAKCgoKCjxkZXRhaWxzPgo8c3VtbWFyeT5UcnlpbmcgZGlmZmVyZW50IGRpc3RhbmNlIGRlY2F5IHJhdGVzLCBzZWFjZWxsIGFnZ3JlYWdhdGVzPC9zdW1tYXJ5PgoKU0VBY2VsbHMgCgpgYGB7ciwgZmlnLndpZHRoPTYsIGZpZy5oZWlnaHQ9Nn0KIyBwcmVwYXJlIGxpc3RzIHRvIHN0b3JlIGNvcnJlbGF0aW9uIHZlY3RvcnMgYW5kIGNvcnJlbGF0aW9uIGhpc3RvZ3JhbXMKY29ycl9saXN0IDwtIGxpc3Qoc2VhY2VsbF9jb3JyX2FyY2hyW1sxXV0sIHNlYWNlbGxfY29ycl9wMmdbWzFdXSkKCm1vZGVsX2xpc3QgPC0gYygiZXhwKC1hYnMoZGlzdGFuY2UpLzUwMDApIiwgImV4cCgtYWJzKGRpc3RhbmNlKS81MDAwMCkiLAogICAgICAgICAgICAgICAgImV4cCgtYWJzKGRpc3RhbmNlKS81MDAwMDApIiwgImV4cCgtYWJzKGRpc3RhbmNlKS81MDAwMDAwKSIpCgojIGNvbXB1dGUgdGhlIGRpc3RhbmNlLXdlaWdodGVkIGdlbmUgYWN0aXZpdHkgc2NvcmVzIGZyb20gcDJnIGxpbmtzIHVzaW5nIGRpZmZlcmVudCAKIyBkaXN0YW5jZSB3ZWlnaHQgbW9kZWxzCmZvciAobW9kZWwgaW4gbW9kZWxfbGlzdCl7CiAgd2VpZ2h0ZWRfc2NvcmVzIDwtIGRpc3RhbmNfd2VpZ2h0ZWRfZ2VuZV9hY3Rpdml0eV9zY29yZXMocDJnX21hdF9zdWIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlbmVNb2RlbCA9IG1vZGVsLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3ZWlnaHQgPSA1MDAwMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwZWFrX21hdCA9IFBFQUtfTUFULAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpbmtzID0gbGlua3MsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHAyZ19vcmlnaW5hbCA9IHAyZywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VuZV9hbm5vID0gR0VORV9BTk5PKQogIGFnZ19kaXN0IDwtIGNyZWF0ZV9zZWFjZWxsX2FnZ3JlZ2F0ZXMod2VpZ2h0ZWRfc2NvcmVzLCBzZWFjZWxscykKICBkaXN0X2tubiA8LSByb3d3aXNlX2NvcnJlbGF0aW9ucyhzZWFjZWxsX3JuYV9hZ2csIGFnZ19kaXN0LCBuYW1lID0gcGFzdGUwKCJQMmcgYWN0aXZpdHkgc2NvcmVzLCBkaXN0YW5jZSB3ZWlnaHRlZCwgbW9kZWwgPSAiLCBtb2RlbCkpCiAgc3RvcGlmbm90KGFueShpcy5uYShkaXN0X2tubikpID09IEZBTFNFKQogIAogIGNvcnJfbGlzdCA8LSBhcHBlbmQoY29ycl9saXN0LCBkaXN0X2tubltbMV1dKQogIHByaW50KGRpc3Rfa25uW1syXV0pCiAgCiAgZ2dzYXZlKHBhc3RlMCgiS2F0aGkvcGxvdHMvY29ycl9kaXN0YW5jZV93ZWlnaHRzXyIsIG1vZGVsLCAiX3NlYWNlbGxzLnBuZyIpKQogIAogIHBsb3QgPC0gZ2dwbG90KCkgKyAjZ2VvbV9kZW5zaXR5XzJkX2ZpbGxlZChhZXMoeCA9IGNvcnJfbGlzdFtbaV1dLCAKICAgICAgICAgICAgICAgICAgICAgICMgICAgICAgICAgICAgICAgeSA9IGNvcnJfbGlzdFtbMV1dKSwgYWxwaGEgPSAuNSkgKwogIGdlb21fcG9pbnQoYWVzKHggPSBkaXN0X2tubltbMV1dLAogIHkgPSBjb3JyX2xpc3RbWzFdXVtuYW1lcyhkaXN0X2tubltbMV1dKV0pKSArCiAgZ2VvbV9kZW5zaXR5XzJkX2ZpbGxlZChhZXMoCiAgICB4ID0gZGlzdF9rbm5bWzFdXSwKICAgIHkgPSBjb3JyX2xpc3RbWzFdXVtuYW1lcyhkaXN0X2tubltbMV1dKV0gKSwgCiAgICBhbHBoYSA9IDAuNSkgKwogIGdlb21fbGluZShhZXMoCiAgICB4ID0gY29ycl9saXN0W1sxXV1bbmFtZXMoZGlzdF9rbm5bWzFdXSldLAogICAgeSA9IGNvcnJfbGlzdFtbMV1dW25hbWVzKGRpc3Rfa25uW1sxXV0pXSksIGNvbCA9ICJyZWQiKSArCiAgQ09SUl9USEVNRSArCiAgbGFicyh4ID0gIkNvcnJlbGF0aW9uIGdlbmUgZXhwci4gJiBwMmcgYWN0aXZpdHkgc2NvcmVzIiwKICAgICAgICB0aXRsZSA9IHBhc3RlMChtb2RlbCwgIlNFQUNlbGxzIiksCiAgICAgICAgeSA9ICJDb3JyZWxhdGlvbiBnZW5lIGV4cHIuICYgQXJjaFIgZ2VuZSBhY3Rpdml0eSBzY29yZXMiKQogIHByaW50KHBsb3QpCiAgZ2dzYXZlKHBhc3RlMCgiS2F0aGkvcGxvdHMvY29tcF9jb3JyX2Rpc3RhbmNlX3dlaWdodHNfIiwgbW9kZWwsICJfc2VhY2VsbHMucG5nIikpCn0KCmBgYAoKPC9kZXRhaWxzPgoKCgojIEdlbmUgd2luZG93LCBubyBkaXN0YW5jZSB3ZWlnaHRzCgpUaGVyZSBhcmUgdHdvIG9wdGlvbnMgd2hlbiBkZWZpbmluZyB0aGUgZ2VuZSB3aW5kb3cuIE9uZSBvcHRpb24gaXMgdG8gZXh0ZW5kICsvLSAKMTAwYnAgdXAtIGFuZCBkb3duc3RyZWFtIG9mIHRoZSBUU1MuIEhvd2V2ZXIsIHNpbmNlIGdlbmVzIGhhdmUgZGlmZmVyZW50IHNpemVzLApzb21lIGdlbmUgYm9kaWVzIG1pZ2h0IGJlIG11Y2ggbGFyZ2VyIHRoYW4gdGhlc2UgZ2VuZSB3aW5kb3dzLiBUaGUgc2Vjb25kIG9wdGlvbiAKaXMgdG8gZXh0ZW5kIHRoZSBnZW5lIHdpbmRvdyBub3QgZnJvbSB0aGUgVFNTLCBidXQgZnJvbSB0aGUgc3RhcnQgYW5kIGVuZCBjb3JyZGluYXRlIApvZiB0aGUgZ2VuZSBib2R5IHJlc3BlY3RpdmVseS4gVGhpcyB3YXksIG1vcmUgcGVha3Mgd2lsbCBiZSB0YWtlbiBpbnRvIGNvbnNpZGVyYXRpb24gCmlmIGEgZ2VuZSBpcyBsYXJnZXIsIHNpbXBseSBiZWNhdXNlIHRoZSBnZW5lIHdpbmRvdyB3aWxsIGJlIGxhcmdlci4gVGhlcmVmb3JlLCAKaW4gQXJjaFIgdGhleSB1c2UgYW4gYWRkaXRpb25hbCB3ZWlnaHQgZm9yIHRoZSBnZW5lIGJvZHkgc2l6ZSB0byBhY2NvdW50IGZvciB0aGlzCmVmZmVjdC4gSGVyZSwgd2UgZXh0ZW5kIHRoZSBnZW5lIHdpbmRvdyBhcm91bmQgdGhlIFRTUy4gQXMgY2FuIGJlIHNlZW4gaW4gCnRoZSBwbG90IGJlbG93LCB0aGlzIGRvZXMgbm90IHlpZWxkIGJldHRlciByZXN1bHRzLCBwcm9iYWJseSwgYmVjYXVzZSB3ZSBhcmUKcmVtb3ZpbmcgYSBsb3Qgb2YgY29ycmVsYXRpb25zIHdoaWNoIGFyZSBoaWdoIGFuZCwgdGhlcmVmb3JlLCBpbXBvcnRhbnQgZm9yCnRoZSBwcmVkaWN0aW9uLiAKClRoaXMgaXMgbm90IHdoYXQgd291bGQgYmUgZXhwZWN0ZWQsIHNpbmNlIHNvbWUgaGlnaCBjb3JyZWxhdGlvbnMgd2l0aGluCnRoZSBnZW5lIHdpbmRvdyBhcmUgdmVyeSBsaWtlbHkgdG8gYmUgYmlvbG9naWNhbGx5IGltcG9ydGFudCBhbmQgc2hvdWxkCnJlY2FwaXR1bGF0ZSBnZW5lIGV4cHJlc3Npb24gcXVpdGUgd2VsbC4gVGhpcyBpcyBhbHNvIHNob3duIGJ5IHRoZSBBcmNoUiAKZ2VuZSBhY3Rpdml0eSBzY29yZXMsIHdoaWNoIHVzZSBnZW5lIHdpbmRvdyBhcyB3ZWxsIHRvIHJlc3RyaWMgdGhlIGluZmx1ZW5jZQpvZiBhY2Nlc3NpYmxlIHJlZ2lvbnMgdG8gYSBjZXJ0YWluIHdpbmRvdyBhcm91bmQgdGhlIGdlbmUncyBUU1MuIE9uZSByZWFzb24KY291bGQgYmUgdGhhdCB0aGUgcGVhay10by1nZW5lIGxpbmtzIGlkZW50aWZpZWQgYnkgc2ltcGxlIGNvcnJlbGF0aW9ucyBhcmUKbm90IGJpb2xvZ2ljYWxseSBtZWFuaW5nZnVsLCB0aGVyZWZvcmUgYWxzbyB2ZXJ5IGZhciBhd2F5IGNvcnJlbGF0aW9ucyAKYXJlIGltcG9ydGFudCBmb3IgcmVjYXBpdHVsYXRpbmcgZ2VuZSBleHByZXNzaW9uLgoKIyMgR2VuZSB3aW5kb3cgYXJvdW5kIFRTUwoKYGBge3IsIGZpZy53aWR0aD0xNX0KIyBBcyBpbnB1dCBmb3IgdGhpcyBmdW5jdGlvbiBpdCBpcyBiZXN0IHRvIHVzZSBvbmx5IHRoZSBtb3N0IGhpZ2hseSB2YXJpYWJsZSBnZW5lcwpjb21wdXRlX2dlbmVfd2luZG93X3Njb3JlIDwtIGZ1bmN0aW9uKHAyZ19tYXRfc3ViLCBwZWFrX21hdCwgbGlua3MsIHAyZ19vcmlnaW5hbCwgZ2VuZV9hbm5vKXsKICAKICBnZW5lX2Fubm9fb3JpZ2luYWwgPC0gZ2VuZV9hbm5vCiAgIyBjcmVhdGUgZ2VuZSBhbm5vdGF0aW9ucyB3aXRoIHN0YXJ0IGNvb3JkaW5hdGUgb2YgZWFjaCBnZW5lCiAgIyBzdWJzZXQgdG8gY29udGFpbiBvbmx5IGdlbmVzIHdoaWNoIGFyZSBpbmNsdWRlZCBpbiBvdXIgcGVhazJnZW5lIG1hdHJpeAogIGdlbmVfYW5ubyA8LSBnZW5lX2Fubm8gJT4lIAogICAgYXMuZGF0YS5mcmFtZSgpICU+JQogICAgbXV0YXRlKGlkeFJOQSA9IHNlcShucm93KC4pKSkgJT4lIAogICAgZHBseXI6OmZpbHRlcihuYW1lICVpbiUgcm93bmFtZXMocDJnX21hdF9zdWIpKSAlPiUKICAgIG11dGF0ZShzdHJhbmQgPSBpZmVsc2Uoc3RyYW5kID09IDEsICIrIiwgIi0iKSkgJT4lCiAgICBtdXRhdGUoc3RhcnRfY29vcmQgPSBpZmVsc2Uoc3RyYW5kID09ICIrIiwgc3RhcnQsIGVuZCkpICU+JSAKICAgIHJlbmFtZShnZW5lID0gbmFtZSkgIyU+JSBHUmFuZ2VzKCkKCiAgIyBleHRlbmQgZ2VuZSByZWdpb25zICsvLSAxMDBicCB1cC0gYW5kIGRvd25zdHJlYW0gb2YgdGhlIFRTUwogIGdlbmVfcmVnaW9ucyAgPC0gcmVzaXplKGdlbmVfYW5ubyAlPiUgR1JhbmdlcygpLCB3aWR0aCA9IDEpCiAgZXh0ZW5kZWRHZW5lUmVnaW9uIDwtIChzdXBwcmVzc1dhcm5pbmdzKGV4dGVuZEdSKGdlbmVfcmVnaW9ucywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdXBzdHJlYW0gPSAxMDAwMDAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRvd25zdHJlYW0gPSAxMDAwMDApKSkKICAjIHN1YnNldCBhdGFjIGdyYW5nZXMgJiBnZXQgbWlkZGxlIG9mIGVhY2ggcGVhawogIHBvc19hdGFjX2dyYW5nZXMgPC0gIG1ldGFkYXRhKHAyZ19vcmlnaW5hbClbWzFdXSAgJT4lIAogICAgYXMuZGF0YS5mcmFtZSgpICU+JQogICAgbXV0YXRlKGlkeEFUQUMgPSBzZXEobnJvdyguKSkpICU+JSAKICAgICMgZ3JvdXBfYnkoc2VxbmFtZXMpICU+JQogICAgIyBtdXRhdGUoaWR4ID0gc2VxX2Fsb25nKHNlcW5hbWVzKSkgJT4lIAogICAgIyB1bmdyb3VwICU+JQogICAgI3RpZHlyOjp1bml0ZShjaHJfaWR4LCBzZXFuYW1lcywgaWR4LCByZW1vdmUgPSBGQUxTRSwgc2VwID0gIl8iKSAlPiUgCiAgICBkcGx5cjo6ZmlsdGVyKGlkeEFUQUMgJWluJSBjb2xuYW1lcyhwMmdfbWF0X3N1YikpICU+JSAKICAgIG11dGF0ZShtaWRkbGUgPSBzdGFydCArIDMwMCkgIyU+JSBHUmFuZ2VzKCkgCiAgCiAgI1RPRE86IEZpbHRlciBmb3IgZ2VuZXMhCiAgc3RvcGlmbm90KGxlbmd0aCh1bmlxdWUobGlua3MkaWR4QVRBQykpID09IGRpbShwb3NfYXRhY19ncmFuZ2VzKVtbMV1dKQogIHN0b3BpZm5vdChsZW5ndGgodW5pcXVlKGxpbmtzJGlkeFJOQSkpID09IGRpbShnZW5lX2Fubm8pW1sxXV0pCiAgI3AyZ19maWx0IDwtIHAyZ19vcmlnaW5hbCAlPiUgYXMuZGF0YS5mcmFtZSgpICU+JSBmaWx0ZXIoZ2VuZSAlaW4lIHJvd25hbWVzKHAyZ19tYXQpKQogIAogIAogICAgIyBmaW5kIG92ZXJsYXBwaW5nIHBlYWtzIGFuZCBnZW5lIHdpbmRvdyBpbiBjaHJvbW9zb21lLWF3YXJlIGZhc2hpb24KICB0bXAgPC0gc3VwcHJlc3NXYXJuaW5ncyhmaW5kT3ZlcmxhcHMoZXh0ZW5kZWRHZW5lUmVnaW9uLCBwb3NfYXRhY19ncmFuZ2VzICU+JSBHUmFuZ2VzKCkpKQogIAogIHByaW50KHBhc3RlMCgiT3V0IG9mICIsIHN1YmplY3RMZW5ndGgodG1wKSwgIiBwZWFrcyBvbmx5ICIsCiAgICAgICAgICAgICAgIGxlbmd0aCh1bmlxdWUoc3ViamVjdEhpdHModG1wKSkpLCAiIHBlYWtzIGFyZSBmb3VuZCB3aXRoaW4gZ2VuZSB3aW5kb3cgb2YgMjAwa2IuIikpCiAgCiAgCiAgIyMjIHNvbWUgcGxvdHMKICBwMSA8LSAodG1wICU+JSBhcy5kYXRhLmZyYW1lKCkgJT4lIAogICAgICAgICBncm91cF9ieShxdWVyeUhpdHMpICU+JSAjIGdlbmUgcmVnaW9uCiAgICAgICAgIHN1bW1hcml6ZShuID0gbigpKSAlPiUgIyBnZXQgbnVtYmVyIG9mIHBlYWtzIG92ZXJsYXBwaW5nIHdpdGggYSBnZW5lIHJlZ2lvbgogICAgICAgICBnZ3Bsb3QoKSArIGdlb21faGlzdG9ncmFtKGFlcyh4ID0gbiksIGJpbnMgPSAxMDAsIGZpbGw9IiM2OWIzYTIiKSArCiAgICAgICAgIGxhYnModGl0bGUgPSAiR2VuZSB3aW5kb3cgb2Ygc2l6ZSArLy0gMTAwa2IgZnJvbSBUU1MiLAogICAgICAgICAgICAgeCA9ICIjcGVha3Mgd2l0aGluIGdlbmUgd2luZG93IikpICsKICAgIENPUlJfVEhFTUUKICAKICAKICAKICAjIGNvbWJpbmUgdGhlIHRocmVlIGRhdGFmcmFtZXMKICBwMmdfam9pbiA8LSBsZWZ0X2pvaW4obGlua3MsIGFzLmRhdGEuZnJhbWUocG9zX2F0YWNfZ3JhbmdlcyksCiAgICAgICAgICAgICAgICAgICAgICAgIGJ5ID0gImlkeEFUQUMiKQogIHAyZ19qb2luIDwtIGxlZnRfam9pbihwMmdfam9pbiwgYXMuZGF0YS5mcmFtZShnZW5lX2Fubm8pLAogICAgICAgICAgICAgICAgICAgICAgICBieSA9ICJpZHhSTkEiLCBzdWZmaXggPSBjKCIuYXRhYyIsICIucm5hIikpCgogICMgY29tcHV0ZSBkaXN0YW5jZSBhbmQgZGlzdGFuY2Ugd2VpZ2h0cyAKICBwMmdfam9pbiA8LSBwMmdfam9pbiAlPiUgCiAgICBtdXRhdGUoZGlzdGFuY2UgPSBhYnMoc3RhcnRfY29vcmQgLSBtaWRkbGUpKQogIAogIAogIHAyIDwtIHAyZ19qb2luICU+JSBnZ3Bsb3QoKSArCiAgICBnZW9tX2hpc3RvZ3JhbShhZXMoeCA9IGRpc3RhbmNlKSwgYmlucyA9IDEwMCwgZmlsbD0iIzY5YjNhMiIpICsKICAgIGxhYnModGl0bGUgPSAiUDJnIGxpbmtzIHdpdGhpbiArLy0gMTAwa2Igd2luZG93IiwgeCA9ICJEaXN0YW5jZSAoYnApIikgKwogICAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ICA9IDEwMDAwMCwgY29sb3IgPSAib3JhbmdlIikgKwogICAgQ09SUl9USEVNRQoKICAKICAjIHAyIDwtIHAyZ19qb2luICU+JSBnZ3Bsb3QoKSArCiAgIyAgIGdlb21faGlzdG9ncmFtKGFlcyh4ID0gKGRpc3RhbmNlX3dlaWdodCkpLCBiaW5zID0gMTAwKSArCiAgIyAgIHNjYWxlX3lfbG9nMTAoKSArCiAgIyAgIGxhYnModGl0bGUgPSAiRGlzdGFuY2UgV2VpZ2h0cyIsIHggPSAiZGlzdGFuY2Ugd2VpZ2h0cyIpIAoKICBwcmludChjb3dwbG90OjpwbG90X2dyaWQocDEsIHAyLCBuY29sID0gMikpIyksICBuY29sID0gMikpCiAgCiAgCiAgZ2dzYXZlKCJLYXRoaS9wbG90cy9nZW5lX3dpbmRvd19kaXN0YW5jZS5wZGYiKQogIAogICAgCiAgIyBjcmVhdGUgYSBkYXRhZnJhbWUgb2YgYWxsIHBlYWtzIHdoaWNoIG92ZXJsYXAgdGhlaXIgY29ycmVzcG9uZGluZyBnZW5lIHdpbmRvdwogIHBlYWtzX2luX2dlbmVfd2luZG93IDwtIGRhdGEuZnJhbWUoZ2VuZSA9IGdlbmVfcmVnaW9uc1txdWVyeUhpdHModG1wKV0kZ2VuZSwgCiAgICAgICAgICAgICBwZWFrID0gKHBvc19hdGFjX2dyYW5nZXMgJT4lIEdSYW5nZXMoKSlbc3ViamVjdEhpdHModG1wKV0kaWR4QVRBQykgJT4lIAogICAgdW5pdGUocGVha19nZW5lX3dpbmRvdywgZ2VuZSwgcGVhaywgc2VwID0gIiMiLCByZW1vdmUgPSBGQUxTRSkKICAKICAjIGZpbHRlciB0aGUgcDJnIGxpbmsgZGF0YWZyYW1lIGZvciBvbmx5IHBlYWtzIHdoaWNoIGFyZSB3aXRoaW4gYSBnZW5lIHdpbmRvdwogIGNvcnJfd2luZG93IDwtIHAyZ19qb2luICU+JQogICAgdW5pdGUocGVha19nZW5lX3dpbmRvdywgZ2VuZSwgaWR4QVRBQywgc2VwID0gIiMiLCByZW1vdmUgPSBGQUxTRSkgJT4lCiAgICBkcGx5cjo6ZmlsdGVyKHBlYWtfZ2VuZV93aW5kb3cgJWluJSBwZWFrc19pbl9nZW5lX3dpbmRvdyRwZWFrX2dlbmVfd2luZG93KSAKCgogICMjIyBQTE9UUwogIAogIHAxIDwtIGNvcnJfd2luZG93ICU+JSAKICAgIGdncGxvdCgpICsKICAgIGdlb21faGlzdG9ncmFtKGFlcyh4ID0gQ29ycmVsYXRpb24pLCBiaW5zID0gMjAwLCBmaWxsID0gIiM2OWIzYTIiKSArCiAgICBsYWJzKHRpdGxlID0gIlAyZyBsaW5rcyB3aXRoaW4gKy8tIDEwMGtiIGdlbmUgd2luZG93IikgKwogICAgVEhFTUVfTE9ORwogIAogIHAyIDwtIGNvcnJfd2luZG93ICU+JSAKICAgIGdncGxvdCgpICsKICAgIGdlb21faGlzdG9ncmFtKGFlcyh4ID0gZGlzdGFuY2UpLCBiaW5zID0gMjAwLCBmaWxsID0gIiM2OWIzYTIiKSArCiAgICBsYWJzKHggPSAiRGlzdGFuY2UgKGJwKSIpICsKICAgIFRIRU1FX0xPTkcKICAKICBwMyA8LSBjb3JyX3dpbmRvdyAlPiUgCiAgICBtdXRhdGUoYmluID0gY3V0X3dpZHRoKGRpc3RhbmNlLCB3aWR0aD0xMDAwMCwgYm91bmRhcnk9MCkpICU+JSAKICAgIGdncGxvdCgpICsKICAgIGdlb21fdmlvbGluKGFlcyh4ID0gYmluLCB5ID0gQ29ycmVsYXRpb24pLCBmaWxsID0gIiM2OWIzYTIiLCBhbHBoYSA9IC42LCBzY2FsZSA9ICJ3aWR0aCIpICsKICAgIGdlb21fYm94cGxvdChhZXMoeCA9IGJpbiwgeSA9IENvcnJlbGF0aW9uKSwgYWxwaGEgPSAwKSArCiAgICBsYWJzKHRpdGxlID0gIlAyZyBsaW5rcyB3aXRoaW4gKy8tIDEwMGtiIGdlbmUgd2luZG93IiwKICAgICAgICAgeCA9ICJEaXN0YW5jZSAoMTBrcCBiaW5zKSIpICsKICAgIHNjYWxlX3hfZGlzY3JldGUoZ3VpZGUgPSBndWlkZV9heGlzKGFuZ2xlID0gNDUpKSArCiAgICBUSEVNRV9MT05HCgogIHByaW50KGNvd3Bsb3Q6OnBsb3RfZ3JpZChwMSwgcDIsIG5jb2wgPSAxKSkKICAKICBnZ3NhdmUoIkthdGhpL3Bsb3RzL2Rpc3RhbmNlX2NvcnJlbGF0aW9uLnBkZiIpCiAgCiAgcHJpbnQocDMpCiAgZ2dzYXZlKCJLYXRoaS9wbG90cy9EaXN0YW5jZV92c19jb3JyX2dlbmVfd2luZG93LnBkZiIpCiAgCiAgIyBwMSA8LSBnZ3Bsb3QoKSArIAogICMgICBnZW9tX2hpc3RvZ3JhbShhZXMoeCA9IHJvd1N1bXMocDJnX21hdF9zdWIgPiAwKSksIGJpbnMgPSAyMDAsIGZpbGwgPSAiIzY5YjNhMiIpICsKICAjICAgc2NhbGVfeV9sb2cxMCgpICsKICAjICAgbGFicyh0aXRsZSA9ICIjIHBlYWtzIGNvcnJlbGF0ZWQgd2l0aCBlYWNoIGdlbmUiLCAKICAjICAgICAgICB4ID0gIm51bWJlciBvZiBwZWFrcyIsIHkgPSAibG9nMTAoY291bnQpIikgCiAgIyAgIAogICMgCiAgIyBwMiA8LSBnZ3Bsb3QoKSArIAogICMgICBnZW9tX2hpc3RvZ3JhbShhZXMoeCA9IGNvbFN1bXMocDJnX21hdF9zdWIgPiAwKSksIGJpbnMgPSA3MCwgZmlsbCA9ICIjNjliM2EyIikgKwogICMgICBzY2FsZV95X2xvZzEwKCkgKwogICMgICBsYWJzKHRpdGxlID0gIiMgZ2VuZXMgY29ycmVsYXRlZCB3aXRoIGVhY2ggcGVhayIsCiAgIyAgICAgICAgeSA9ICJsb2cxMChjb3VudCkiLCB4ID0gIm51bWJlciBvZiBnZW5lcyIpCiAgCiAgcDMgPC0gZ2dwbG90KCkgKyAKICAgIGdlb21faGlzdG9ncmFtKGFlcyh4ID0gcm93U3VtcyhwMmdfbWF0X3N1YiA+IDApKSwgYmlucyA9IDIwMCwgZmlsbCA9ICIjNjliM2EyIikgKwogICAgbGFicyh0aXRsZSA9ICIjIHBlYWtzIGNvcnJlbGF0ZWQgd2l0aCBlYWNoIGdlbmUiLCAKICAgICAgICAgeCA9ICJudW1iZXIgb2YgcGVha3MiLCB5ID0gImNvdW50IikgKwogICAgQ09SUl9USEVNRQogICAgCiAgCiAgcDQgPC0gZ2dwbG90KCkgKyAKICAgIGdlb21faGlzdG9ncmFtKGFlcyh4ID0gY29sU3VtcyhwMmdfbWF0X3N1YiA+IDApKSwgYmlucyA9IDcwLCBmaWxsID0gIiM2OWIzYTIiKSArCiAgICBsYWJzKHRpdGxlID0gIiMgZ2VuZXMgY29ycmVsYXRlZCB3aXRoIGVhY2ggcGVhayIsCiAgICAgICAgIHkgPSAiY291bnQiLCB4ID0gIm51bWJlciBvZiBnZW5lcyIpICsKICAgIENPUlJfVEhFTUUKICAKICBwcmludChjb3dwbG90OjpwbG90X2dyaWQocDMsIHA0LCBuY29sID0gMikpCgogIAogIGdnc2F2ZSgiS2F0aGkvcGxvdHMvZ2VuZXNfcGVha3NfY29ycmVsYXRpb25zLnBkZiIpCiAgCiAgCiAjIENyZWF0ZSBhIG1hdHJpeCBvZiBkaXN0YW5jZSB3ZWlnaHQgCiAgcDJnX2xpbmtzX2dlbmVfd2luZG93IDwtIE1hdHJpeDo6c3BhcnNlTWF0cml4KAogICAgICBpID0gY29ycl93aW5kb3ckaWR4Uk5BLCAKICAgICAgaiA9IGNvcnJfd2luZG93JGlkeEFUQUMsIAogICAgICB4ID0gY29ycl93aW5kb3ckQ29ycmVsYXRpb24sIAogICAgICBkaW1zID0gYyhucm93KGdlbmVfYW5ub19vcmlnaW5hbCksIG5yb3cocGVha19tYXQpKSwKICAgICAgZGltbmFtZXMgPSBsaXN0KGdlbmVfYW5ub19vcmlnaW5hbCRuYW1lLAogICAgICAgICAgICAgICAgICAgICAgc2VxLmludChucm93KHBlYWtfbWF0KSkpCiAgICApCiAgCiAgCiAgCiAgcHJpbnQocGFzdGUwKCJUaGUgcGVhay10by1nZW5lIGxpbmtzIG1hdHJpeCwgcmVzdHJpY3RlZCB0byBhICsvLSAxMDBrYiB3aW5kb3cgYXJvdW5kIHRoZSBUU1MgaGFzIGRpbWVuc2lvbnMgIiwgc3BsaXQoZGltKHAyZ19saW5rc19nZW5lX3dpbmRvdyksIDEpKSkKICAKICBwcmludChwYXN0ZTAoIlRoZSBtYXhpbXVtIHZhbHVlIGlzOiAiLCBtYXgocDJnX2xpbmtzX2dlbmVfd2luZG93KSwgIiwgdGhlIG1pbmltdW0gdmFsdWUgaXM6ICIsIG1pbihwMmdfbGlua3NfZ2VuZV93aW5kb3cpICkpCiAgCiAgCiAgIyByZW1vdmUgYW55IHJvd3Mgb3IgY29sdW1ucyB3aXRoIHplcm9zCiAgcDJnX2xpbmtzX2dlbmVfd2luZG93IDwtIHAyZ19saW5rc19nZW5lX3dpbmRvd1tyb3dTdW1zKHAyZ19saW5rc19nZW5lX3dpbmRvdykgIT0gMCwgXQogIHAyZ19saW5rc19nZW5lX3dpbmRvdyA8LSBwMmdfbGlua3NfZ2VuZV93aW5kb3dbLCBjb2xTdW1zKHAyZ19saW5rc19nZW5lX3dpbmRvdykgIT0gMF0KICAKICBwcmludChwYXN0ZTAoIkFmdGVyIHJlbW92aW5nIGFueSByb3dzIGFuZCBjb2x1bXNuIHdoaWNoIGRvIG5vdCBjb250YWluIGFueSBsaW5rcyB3ZSBhcmUgbGVmdCB3aXRoICIsIG5yb3cocDJnX2xpbmtzX2dlbmVfd2luZG93KSwgIiBnZW5lcyBhbmQgIiwgbmNvbChwMmdfbGlua3NfZ2VuZV93aW5kb3cpLCAiIHBlYWtzLiIpKQogIAogICMgQ29tcHV0ZSBnZW5lIGFjdGl2aXR5IHNjb3JlcyB3aXRoIHdlaWdodGVkIGRpc3RhbmNlIG1hdGl4CiAgZ2VuZV93aW5kb3dfc2NvcmVzIDwtIGdlbmVfYWN0aXZpdHlfc2NvcmVzKHBlYWtfbWF0X3N1Yltjb2xuYW1lcyhwMmdfbGlua3NfZ2VuZV93aW5kb3cpLCBdLCBwMmdfbGlua3NfZ2VuZV93aW5kb3cpCgogIAogIHJldHVybihnZW5lX3dpbmRvd19zY29yZXMpIAp9CmBgYAoKCmBgYHtyLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0xMH0KZ2VuZV93aW5kb3dfc2NvcmVzIDwtIGNvbXB1dGVfZ2VuZV93aW5kb3dfc2NvcmUoCiAgcDJnX21hdF9zdWIgPSBwMmdfbWF0X3N1YiwgCiAgcGVha19tYXQgPSBQRUFLX01BVCwgCiAgbGlua3MgPSBsaW5rcywgCiAgcDJnX29yaWdpbmFsID0gcDJnLCAKICBnZW5lX2Fubm8gPSBHRU5FX0FOTk8pCmBgYAoKCgoKIyMjIFNFQUNlbGxzCgpTZWNvbmQsIEkgY29tcGFyZWQgdGhlIGRpc3RhbmNlIHdlaWd0aHMgdXNpbmcgdGhlIFNFQUNlbGwgYWdncmVnYXRlcywgd2hpY2gKeWllbGRzIGJldHRlciByZXN1bHRzIGFzIGNhbiBiZSBzZWVuIGFib3ZlLiAKCmBgYHtyLCBmaWcud2lkdGg9NiwgZmlnLmhlaWdodD02fQpnZW5lX3dpbmRvd19hZ2cgPC0gY3JlYXRlX3NlYWNlbGxfYWdncmVnYXRlcyhnZW5lX3dpbmRvd19zY29yZXMsIHNlYWNlbGxzKQpnZW5lX3dpbmRvd19jb3JyIDwtIHJvd3dpc2VfY29ycmVsYXRpb25zKHNlYWNlbGxfcm5hX2FnZywgZ2VuZV93aW5kb3dfYWdnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPSAiR2VuZSB3aW5kb3cgYXJvdW5kIFRTUyIpCgpnZW5lX3dpbmRvd19jb3JyW1syXV0KZ2dzYXZlKCJLYXRoaS9wbG90cy9jb3JyZWxhdGlvbl9wMmdfZ2VuZV93aW5kb3dfYXJjaHIucGRmIikKCgpnZ3Bsb3QoKSArCiAgZ2VvbV9wb2ludChhZXMoeCA9IGdlbmVfd2luZG93X2NvcnJbWzFdXSwKICAgICAgICAgICAgICAgICB5ID0gc2VhY2VsbF9jb3JyX2FyY2hyW1sxXV1bbmFtZXMoZ2VuZV93aW5kb3dfY29ycltbMV1dKV0pKSArCiAgZ2VvbV9kZW5zaXR5XzJkX2ZpbGxlZChhZXMoCiAgICB5ID0gc2VhY2VsbF9jb3JyX2FyY2hyW1sxXV1bbmFtZXMoZ2VuZV93aW5kb3dfY29ycltbMV1dKV0sCiAgICB4ID0gZ2VuZV93aW5kb3dfY29ycltbMV1dKSwgYWxwaGEgPSAwLjUpICsKICBnZW9tX2xpbmUoYWVzKHggPSBzZWFjZWxsX2NvcnJfYXJjaHJbWzFdXVtuYW1lcyhnZW5lX3dpbmRvd19jb3JyW1sxXV0pXSwgCiAgICAgICAgICAgICAgICB5ID0gc2VhY2VsbF9jb3JyX2FyY2hyW1sxXV1bbmFtZXMoZ2VuZV93aW5kb3dfY29ycltbMV1dKV0pLCAKICAgICAgICAgICAgY29sb3IgPSAicmVkIikgKwogIENPUlJfVEhFTUUgKwogIGxhYnMoeCA9ICJDb3JyZWxhdGlvbiBnZW5lIGV4cHIuICYgcDJnIGFjdGl2aXR5IHNjb3JlcyIsCiAgICAgICAgeSA9ICJDb3JyZWxhdGlvbiBnZW5lIGV4cHJlc3Npb24gJiBBcmNoUiBnZW5lIGFjdGl2aXR5IHNjb3JlcyIsCiAgICAgICB0aXRsZSA9ICJQZWFrLXRvLWdlbmUgbGlua3Mgd2l0aGluIGdlbmUgd2luZG93IikKCmdnc2F2ZSgiS2F0aGkvcGxvdHMvY29tcGFyZV9jb3JyZWxhdGlvbl9wMmdfZ2VuZV93aW5kb3dfYXJjaHIucGRmIikKCmBgYAoKIyBFZmZlY3Qgb2YgdXNpbmcgZGlmZmVyZW50IGRpc3RhbmNlIGRlY2F5IHJhdGVzIAoKSG93IGRvZXMgdGhlIGRpc3RhbmNlIHdlaWdodCBkaXN0cmlidXRpb24gY2hhbmdlIHdpdGggZGlmZmVyZW50IGRlY2F5IHJhdGVzPwoKSGVyZSwgd2UgdXNlIHRoZSBmb3JtdWxhICRlXntcZnJhY3stYWJzKGRpc3RhbmNlKX17Y319JCB3aXRoIGRpZmZlcmVuIGRlY2F5IHJhdGVzCiRjIFxpbiBcezUwMDAsIDUwMDAwLCA1MDAwMDAsIDUwMDAwMDBcfSQuIEFkZGl0aW9uYWxseSwgd2UgdXNlIG9ubHkgcGVha3Mgd2hpY2ggCm92ZXJsYXAgd2l0aCBhICsvLSAxMDBrYiB3aW5kb3cgZnJvbSB0aGUgVFNTLgoKYGBge3IsIGZpZy53aWR0aD0xMCxmaWcuaGVpZ2h0PTZ9Cm1vZGVsX2xpc3QgPC0gYygiZXhwKC1hYnMoZGlzdGFuY2UpLzUwMDApIiwgImV4cCgtYWJzKGRpc3RhbmNlKS81MDAwMCkiLAogICAgICAgICAgICAgICAgImV4cCgtYWJzKGRpc3RhbmNlKS81MDAwMDApIiwgImV4cCgtYWJzKGRpc3RhbmNlKS81MDAwMDAwKSIpCgoKYXRhY19ncmFuZ2VzIDwtIG1ldGFkYXRhKHAyZylbWzFdXQojcm5hX2dyYW5nZXMgPC0gbWV0YWRhdGEocDJnX29yaWdpbmFsKVtbMl1dCmdlbmVfYW5ubyA8LSBHRU5FX0FOTk8KCiMgY3JlYXRlIGdlbmUgYW5ub3RhdGlvbnMgd2l0aCBzdGFydCBjb29yZGluYXRlIG9mIGVhY2ggZ2VuZQojIHN1YnNldCB0byBjb250YWluIG9ubHkgZ2VuZXMgd2hpY2ggYXJlIGluY2x1ZGVkIGluIG91ciBwZWFrMmdlbmUgbWF0cml4CmdlbmVfYW5ubyA8LSBnZW5lX2Fubm8gJT4lIGFzLmRhdGEuZnJhbWUoKSAlPiUKICBtdXRhdGUoaWR4Uk5BID0gc2VxKG5yb3coLikpKSAlPiUgCiAgZHBseXI6OmZpbHRlcihuYW1lICVpbiUgcm93bmFtZXMocDJnX21hdF9zdWIpKSAlPiUKICBtdXRhdGUoc3RyYW5kID0gaWZlbHNlKHN0cmFuZCA9PSAxLCAiKyIsICItIikpICU+JQogIG11dGF0ZShzdGFydF9jb29yZCA9IGlmZWxzZShzdHJhbmQgPT0gIisiLCBzdGFydCwgZW5kKSkgJT4lIAogIHJlbmFtZShnZW5lID0gbmFtZSkgIyU+JSBHUmFuZ2VzKCkKCiMgc3Vic2V0IGF0YWMgZ3JhbmdlcyAmIGdldCBtaWRkbGUgb2YgZWFjaCBwZWFrCnBvc19hdGFjX2dyYW5nZXMgPC0gYXRhY19ncmFuZ2VzICAlPiUgCiAgYXMuZGF0YS5mcmFtZSgpICU+JQogIG11dGF0ZShpZHhBVEFDID0gc2VxKG5yb3coLikpKSAlPiUgCiAgIyBncm91cF9ieShzZXFuYW1lcykgJT4lCiAgIyBtdXRhdGUoaWR4ID0gc2VxX2Fsb25nKHNlcW5hbWVzKSkgJT4lIAogICMgdW5ncm91cCAlPiUKICAjdGlkeXI6OnVuaXRlKGNocl9pZHgsIHNlcW5hbWVzLCBpZHgsIHJlbW92ZSA9IEZBTFNFLCBzZXAgPSAiXyIpICU+JSAKICBkcGx5cjo6ZmlsdGVyKGlkeEFUQUMgJWluJSBjb2xuYW1lcyhwMmdfbWF0X3N1YikpICU+JSAKICBtdXRhdGUobWlkZGxlID0gc3RhcnQgKyAzMDApICMlPiUgR1JhbmdlcygpIAoKCgojIGNvbWJpbmUgdGhlIHRocmVlIGRhdGFmcmFtZXMKcDJnX2pvaW4gPC0gbGVmdF9qb2luKGxpbmtzLCBhcy5kYXRhLmZyYW1lKHBvc19hdGFjX2dyYW5nZXMpLAogICAgICAgICAgICAgICAgICAgICAgYnkgPSAiaWR4QVRBQyIpCnAyZ19qb2luIDwtIGxlZnRfam9pbihwMmdfam9pbiwgYXMuZGF0YS5mcmFtZShnZW5lX2Fubm8pLAogICAgICAgICAgICAgICAgICAgICAgYnkgPSAiaWR4Uk5BIiwgc3VmZml4ID0gYygiLmF0YWMiLCAiLnJuYSIpKQoKIyBjb21wdXRlIGRpc3RhbmNlIGFuZCBkaXN0YW5jZSB3ZWlnaHRzIApwMmdfam9pbiA8LSBwMmdfam9pbiAlPiUgCiAgbXV0YXRlKGRpc3RhbmNlID0gYWJzKHN0YXJ0X2Nvb3JkIC0gbWlkZGxlKSkgJT4lCiAgbXV0YXRlKHJlbF9kaXN0YW5jZSA9IHN0YXJ0X2Nvb3JkIC0gbWlkZGxlKQogIyBtdXRhdGUoZGlzdGFuY2Vfd2VpZ2h0ID0gZXZhbChwYXJzZSh0ZXh0PWdlbmVNb2RlbCkpKQpgYGAKCjxkZXRhaWxzPgoKPHN1bW1hcnk+ZGlzdHJpYnV0aW9uIG9mIGRpc3RhbmNlIHdlaWdodHMgdXNpbmcgZGlmZmVyZW50IGRpc3RhbmNlIGRlY2F5IHJhdGVzPC9zdW1tYXJ5PgoKYGBge3IsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD02fQpmb3IgKG1vZGVsIGluIG1vZGVsX2xpc3QpeyAKIyBjb21wdXRlIGRpc3RhbmNlIGFuZCBkaXN0YW5jZSB3ZWlnaHRzIAogIHAyZ19qb2luIDwtIHAyZ19qb2luICU+JSAKICAgIG11dGF0ZShkaXN0YW5jZSA9IGFicyhzdGFydF9jb29yZCAtIG1pZGRsZSkpICU+JQogICAgbXV0YXRlKGRpc3RhbmNlX3dlaWdodCA9IGV2YWwocGFyc2UodGV4dD1tb2RlbCkpKQogIAogIHAxIDwtIHAyZ19qb2luICU+JSBnZ3Bsb3QoKSArCiAgICBnZW9tX2hpc3RvZ3JhbShhZXMoeCA9IGRpc3RhbmNlKSwgYmlucyA9IDIwMCwgZmlsbD0iIzY5YjNhMiIpICsKICAgIGxhYnModGl0bGUgPSAiRGlzdGFuY2UgYmV0d2VlbiBwZWFrcyBhbmQgZ2VuZXMiLCB4ID0gImRpc3RhbmNlIikgKwogICAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ICA9IDUwMDAsIGNvbG9yID0gInJlZCIpICsKICAgIGdlb21fdmxpbmUoeGludGVyY2VwdCAgPSAyNTAwMDAsIGNvbG9yID0gIm9yYW5nZSIpICsKICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLAogICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMjApLCAjIGNoYW5nZSBzaXplIG9mIGF4aXMgdGl0bGUKICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIwKSwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBzaXplID0gMjApLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJOb25lIiwgCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAiZ3JleSIpLCAgICMgTWFqb3IgZ3JpZCBsaW5lcwogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ3aGl0ZSIsIGNvbG91ciA9ICJibGFjayIpLAogICAgICAgIGFzcGVjdC5yYXRpbyA9IDEuMikKICAKICBwMiA8LSBwMmdfam9pbiAlPiUgZ2dwbG90KCkgKwogICAgZ2VvbV9oaXN0b2dyYW0oYWVzKHggPSAoZGlzdGFuY2Vfd2VpZ2h0KSksIGJpbnMgPSAyMDAsIGZpbGw9IiM2OWIzYTIiKSArCiAgICBzY2FsZV95X2xvZzEwKCkgKwogICAgbGFicyh0aXRsZSA9IHBhc3RlMChtb2RlbCksCiAgICAgICAgIHggPSAiZGlzdGFuY2Ugd2VpZ2h0cyIsIHkgPSAibG9nMTAoY291bnRzKSIpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLAogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAyMCksICMgY2hhbmdlIHNpemUgb2YgYXhpcyB0aXRsZQogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMjApLAogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIHNpemUgPSAyMCksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIk5vbmUiLCAKICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9saW5lKGNvbG91ciA9ICJncmV5IiksICAgIyBNYWpvciBncmlkIGxpbmVzCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIndoaXRlIiwgY29sb3VyID0gImJsYWNrIiksCiAgICAgICAgYXNwZWN0LnJhdGlvID0gMS4yKQogIAogIHByaW50KGNvd3Bsb3Q6OnBsb3RfZ3JpZChwMSwgcDIsIG5jb2wgPSAyKSkKICAKICBnZ3NhdmUocGFzdGUwKCJLYXRoaS9wbG90cy9kaXN0YW5jZV93ZWlnaHRzIiwgbW9kZWwsICIucGRmIikpCgp9CiAgIyBSZWxhdGlvbnNoaXAgYmV0d2VlbiBkaXN0YW5jZSBhbmQgY29ycmVsYXRpb24gdmFsdWUKIyBwMyA8LSBwMmdfam9pbiAlPiUgZ2dwbG90KCkgKwojICAgZ2VvbV9wb2ludChhZXMoeCA9IENvcnJlbGF0aW9uLCB5ID0gZGlzdGFuY2UpKSArCiMgICBsYWJzKHRpdGxlID0gIkRpc3RhbmNlIHZzLiBjb3JyZWxhdGlvbiBiZXR3ZWVuIHBlYWtzIGFuZCBnZW5lcyIsCiMgICAgICAgIHggPSAiQ29ycmVsYXRpb24gYmV0d2VlbiBwZWFrIGFuZCBnZW5lIiwgCiMgICAgICAgIHkgPSAiRGlzdGFuY2UgYmV0d2VlbiBwZWFrIGFuZCBnZW5lIikKIyAKIyAKIyBwNCA8LSBwMmdfam9pbiAlPiUgZ2dwbG90KCkgKwojICAgZ2VvbV9wb2ludChhZXMoeCA9IENvcnJlbGF0aW9uLCB5ID0gZGlzdGFuY2Vfd2VpZ2h0KSkgKwojICAgbGFicyh0aXRsZSA9ICJEaXN0YW5jZSB2cy4gY29ycmVsYXRpb24gYmV0d2VlbiBwZWFrcyBhbmQgZ2VuZXMiLAojICAgICAgICB4ID0gIkNvcnJlbGF0aW9uIGJldHdlZW4gcGVhayBhbmQgZ2VuZSIsIAojICAgICAgICB5ID0gIkRpc3RhbmNlIHdlaWdodHMgYmV0d2VlbiBwZWFrIGFuZCBnZW5lIikKCgojY293cGxvdDo6cGxvdF9ncmlkKHAxLCBwMiwgbmNvbCA9IDEpCgpgYGAKCjwvc3VtbWFyeT4KCiMjIyBSZWxhdGlvbnNoaXAgYmV0d2VlbiBkaXN0YW5jZSBhbmQgY29ycmVsYXRpb24gdmFsdWVzCgpgYGAje3IsZmlnLndpZHRoPTE1fQoKIyBPbG90IHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGRpc3RhbmNlIGFuZCBjb3JyZWxhdGlvbiBhcyBkZW5zaXR5IHBsb3RzCnAxIDwtIHAyZ19qb2luICU+JSBnZ3Bsb3QoKSArIAogIGdlb21fZGVuc2l0eV8yZF9maWxsZWQoYWVzKHggPSBDb3JyZWxhdGlvbiwgeSA9IGRpc3RhbmNlKSkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJOb25lIikgKwogIGxhYnModGl0bGUgPSAiUmVsYXRpb25zaGlwIGJldHdlZW4gZGlzdGFuY2UgYW5kIGNvcnJlbGF0aW9uIikKCnAyIDwtIHAyZ19qb2luICU+JQogIGZpbHRlcihDb3JyZWxhdGlvbiA+IDAuMykgJT4lIAogIGdncGxvdCgpICsgCiAgZ2VvbV9kZW5zaXR5XzJkX2ZpbGxlZChhZXMoeCA9IENvcnJlbGF0aW9uLCB5ID0gZGlzdGFuY2UpKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIk5vbmUiKSArCiAgbGFicyh0aXRsZSA9ICJSZWxhdGlvbnNoaXAgYmV0d2VlbiBkaXN0YW5jZSBhbmQgY29ycmVsYXRpb24iKQoKcDMgPC0gcDJnX2pvaW4gJT4lCiAgZmlsdGVyKENvcnJlbGF0aW9uID4gMC42KSAlPiUgCiAgZ2dwbG90KCkgKyAKICBnZW9tX2RlbnNpdHlfMmRfZmlsbGVkKGFlcyh4ID0gQ29ycmVsYXRpb24sIHkgPSBkaXN0YW5jZSkpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiTm9uZSIpICsKICBsYWJzKHRpdGxlID0gIlJlbGF0aW9uc2hpcCBiZXR3ZWVuIGRpc3RhbmNlIGFuZCBjb3JyZWxhdGlvbiIpCgpjb3dwbG90OjpwbG90X2dyaWQocDEsIHAyLCBwMywgbmNvbCA9IDIpCmBgYAoKCmBgYCN7cn0KcDJnICU+JSAgCiAgbXV0YXRlKGJpbj1jdXRfd2lkdGgoZGlzdGFuY2UsIHdpZHRoPTEwMDAwMCwgYm91bmRhcnk9MCkpICU+JQogIGZpbHRlcihkaXN0YW5jZSA8IDEwMDAwMDAwKSAlPiUgCiAgZ2dwbG90KCkgKwogIGdlb21fYm94cGxvdChhZXMoeCA9IGJpbiwgeSA9IENvcnJlbGF0aW9uKSwgZmlsbD0iIzY5YjNhMiIpICsKICAjZ2VvbV92bGluZSh4aW50ZXJjZXB0ICA9IDI1MDAwMCwgY29sb3IgPSAicmVkIikgKwogIGxhYnModGl0bGUgPSAiUmVsYXRpb25zaGlwIGJldHdlZW4gZGlzdGFuY2UgYW5kIGNvcnJlbGF0aW9uIG9mIHAyZyBsaW5rcywgMTAwa2IgYmlucyIsCiAgICAgICB4ID0gIkRpc3RhbmNlIGJldHdlZW4gcGVha3MgYW5kIGdlbmVzIHdpdGhpbiAyNTBrYiIsIHkgPSAiQ29ycmVsYXRpb24iKSArIAogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gMC41LCBoanVzdD0xKSkKYGBgCgoKCgoKYGBge3IsIGZpZy53aWR0aD0xNSwgZmlnLmhlaWdodD02fQpwMmdfam9pbiAlPiUgIAogIG11dGF0ZShiaW49Y3V0X3dpZHRoKGRpc3RhbmNlLCB3aWR0aD0xMDAwMDAsIGJvdW5kYXJ5PTApKSAlPiUKICBkcGx5cjo6ZmlsdGVyKGRpc3RhbmNlIDwgMTAwMDAwMDApICU+JSAKICBnZ3Bsb3QoKSArCiAgZ2VvbV92aW9saW4oYWVzKHggPSBiaW4sIHkgPSBDb3JyZWxhdGlvbiksIGZpbGwgPSAiIzY5YjNhMiIsIGFscGhhID0gLjYsIHNjYWxlID0gIndpZHRoIikgKwogIGdlb21fYm94cGxvdChhZXMoeCA9IGJpbiwgeSA9IENvcnJlbGF0aW9uKSwgYWxwaGEgPSAwKSArCiAgICAjZ2VvbV92bGluZSh4aW50ZXJjZXB0ICA9IDI1MDAwMCwgY29sb3IgPSAicmVkIikgKwogIGxhYnModGl0bGUgPSAiUDJnIGxpbmtzLCBlbnRpcmUgY2hyb21zb21lIiwKICAgICAgIHggPSAiRGlzdGFuY2UgKDEwMGtiKSIsIHkgPSAiQ29ycmVsYXRpb24iKSArIAogIENVU1RPTV9USEVNRQogICN0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSwgaGp1c3Q9MSkpCgpnZ3NhdmUoIkthdGhpL3Bsb3RzL3JlbGF0aW9uc2hpcF9kaXN0X2NvcnJfMTBNYi5wZGYiKQpgYGAKCjxkZXRhaWxzPgo8c3VtbWFyeT5GaWd1cmVzIGZvciBSZXBvcnQ8L3N1bW1tYXJ5PgoKYGBge3IsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEyfQoKcDEgPC0gcDJnX2pvaW4gJT4lICAKICBtdXRhdGUoYmluPWN1dF93aWR0aChkaXN0YW5jZSwgd2lkdGg9MTAwMDAwLCBib3VuZGFyeT0wKSkgJT4lCiAgZHBseXI6OmZpbHRlcihkaXN0YW5jZSA8IDEwMDAwMDAwICYgQ29ycmVsYXRpb24gPiAwLjUpICU+JSAKICBnZ3Bsb3QoKSArCiAgZ2VvbV92aW9saW4oYWVzKHggPSBiaW4sIHkgPSBDb3JyZWxhdGlvbiksIGZpbGwgPSAiIzY5YjNhMiIsIGFscGhhID0gLjYsIHNjYWxlID0gIndpZHRoIikgKwogIGdlb21fYm94cGxvdChhZXMoeCA9IGJpbiwgeSA9IENvcnJlbGF0aW9uKSwgYWxwaGEgPSAwKSArCiAgbGFicyh0aXRsZSA9ICJSZWxhdGlvbnNoaXAgYmV0d2VlbiBkaXN0YW5jZSBhbmQgY29ycmVsYXRpb24gb2YgcDJnIGxpbmtzLCAxMDBrYiBiaW5zIiwKICAgICAgIHggPSAiRGlzdGFuY2UgPCAxZV43IGJwIiwgeSA9ICJDb3JyZWxhdGlvbiA+IDAuNSIpICsgCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZT0iU2V0MyIpICsKICBDVVNUT01fVEhFTUUKICAjdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjUsIGhqdXN0PTEpKQoKcHJpbnQocDEpCmdnc2F2ZSgiS2F0aGkvcGxvdHMvUmVsYXRpb25zaGlwX2Rpc3RfY29ycl9kaWZmX3ZhbHVlc18xLnBkZiIpCgoKcDIgPC0gcDJnX2pvaW4gJT4lICAKICBtdXRhdGUoYmluPWN1dF93aWR0aChkaXN0YW5jZSwgd2lkdGg9MTAwMDAwLCBib3VuZGFyeT0wKSkgJT4lCiAgZHBseXI6OmZpbHRlcihkaXN0YW5jZSA8IDEwMDAwMDAwICYgQ29ycmVsYXRpb24gPiAwLjgpICU+JSAKICBnZ3Bsb3QoKSArCiAgZ2VvbV92aW9saW4oYWVzKHggPSBiaW4sIHkgPSBDb3JyZWxhdGlvbiksIGZpbGwgPSAiIzY5YjNhMiIsIGFscGhhID0gLjYsIHNjYWxlID0gIndpZHRoIikgKwogIGdlb21fYm94cGxvdChhZXMoeCA9IGJpbiwgeSA9IENvcnJlbGF0aW9uKSwgYWxwaGEgPSAwKSArCiAgbGFicyh0aXRsZSA9ICJSZWxhdGlvbnNoaXAgYmV0d2VlbiBkaXN0YW5jZSBhbmQgY29ycmVsYXRpb24gb2YgcDJnIGxpbmtzLCAxMDBrYiBiaW5zIiwKICAgICAgIHggPSAiRGlzdGFuY2UgPCAxZV43IGJwIiwgeSA9ICJDb3JyZWxhdGlvbiA+IDAuOCIpICsgCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZT0iU2V0MyIpICsKICBDVVNUT01fVEhFTUUKCnByaW50KHAyKQpnZ3NhdmUoIkthdGhpL3Bsb3RzL1JlbGF0aW9uc2hpcF9kaXN0X2NvcnJfZGlmZl92YWx1ZXNfMi5wZGYiKQoKcDMgPC0gcDJnX2pvaW4gJT4lICAKICBtdXRhdGUoYmluPWN1dF93aWR0aChkaXN0YW5jZSwgd2lkdGg9MTAwMDAwLCBib3VuZGFyeT0wKSkgJT4lCiAgZHBseXI6OmZpbHRlcihkaXN0YW5jZSA8IDEwMDAwMDAwICYgQ29ycmVsYXRpb24gPCAwLjUpICU+JSAKICBnZ3Bsb3QoKSArCiAgZ2VvbV92aW9saW4oYWVzKHggPSBiaW4sIHkgPSBDb3JyZWxhdGlvbiksIGZpbGwgPSAiIzY5YjNhMiIsIGFscGhhID0gLjYsIHNjYWxlID0gIndpZHRoIikgKwogIGdlb21fYm94cGxvdChhZXMoeCA9IGJpbiwgeSA9IENvcnJlbGF0aW9uKSwgYWxwaGEgPSAwKSArCiAgbGFicyh0aXRsZSA9ICJSZWxhdGlvbnNoaXAgYmV0d2VlbiBkaXN0YW5jZSBhbmQgY29ycmVsYXRpb24gb2YgcDJnIGxpbmtzLCAxMDBrYiBiaW5zIiwKICAgICAgIHggPSAiRGlzdGFuY2UgPCAxZV43IGJwIiwgeSA9ICJDb3JyZWxhdGlvbiA8IDAuNSIpICsgCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZT0iU2V0MyIpICsKICBDVVNUT01fVEhFTUUKCnByaW50KHAzKQpnZ3NhdmUoIkthdGhpL3Bsb3RzL1JlbGF0aW9uc2hpcF9kaXN0X2NvcnJfZGlmZl92YWx1ZXNfMy5wZGYiKQoKcDQgPC0gcDJnX2pvaW4gJT4lICAKICBtdXRhdGUoYmluPWN1dF93aWR0aChkaXN0YW5jZSwgd2lkdGg9MTAwMCwgYm91bmRhcnk9MCkpICU+JQogIGRwbHlyOjpmaWx0ZXIoZGlzdGFuY2UgPCAxMDAwMDApICU+JSAjICYgQ29ycmVsYXRpb24gPiAwLjUpICU+JSAKICBnZ3Bsb3QoKSArCiAgZ2VvbV92aW9saW4oYWVzKHggPSBiaW4sIHkgPSBDb3JyZWxhdGlvbiksIGZpbGwgPSAiIzY5YjNhMiIsIGFscGhhID0gLjYsIHNjYWxlID0gIndpZHRoIikgKwogIGdlb21fYm94cGxvdChhZXMoeCA9IGJpbiwgeSA9IENvcnJlbGF0aW9uKSwgYWxwaGEgPSAwKSArCiAgbGFicyh0aXRsZSA9ICJSZWxhdGlvbnNoaXAgYmV0d2VlbiBkaXN0YW5jZSBhbmQgY29ycmVsYXRpb24gb2YgcDJnIGxpbmtzLCAxa2IgYmlucyIsCiAgICAgICB4ID0gIkRpc3RhbmNlIDwgMTAwa2IiKSArIAogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGU9IlNldDMiKSArCiAgQ1VTVE9NX1RIRU1FCgpwcmludChwNCkKZ2dzYXZlKCJLYXRoaS9wbG90cy9SZWxhdGlvbnNoaXBfZGlzdF9jb3JyX2RpZmZfdmFsdWVzXzQucGRmIikKYGBgCgo8L2RldGFpbHM+CgpgYGAje3IsIGZpZy53aWR0aD0xNSwgZmlnLmhlaWdodD0xNX0KY293cGxvdDo6cGxvdF9ncmlkKHAxLCBwMiwgcDMsIHA0LCBuY29sID0gMikKCmBgYAoKCgpMZXRzIGhhdmUgYSBsb29rIGF0IGNvcnJlbGF0aW9uIHZhbHVlcyBiZXR3ZWVuIHBlYWtzIHdpdGhpbiB0aGUgcHJvbW90ZXIgcmVnaW9uCm9mIGEgVFNTLCBuYW1lbHkgNWtiIHVwc3RyZWFtIG9mIHRoZSBUU1MuCgpgYGB7ciwgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTZ9CnAyZ19qb2luICU+JSAgCiAgbXV0YXRlKGJpbj1jdXRfd2lkdGgocmVsX2Rpc3RhbmNlLCB3aWR0aD0xMDAsIGJvdW5kYXJ5PTApKSAlPiUKICBkcGx5cjo6ZmlsdGVyKHJlbF9kaXN0YW5jZSA8IDAgJiByZWxfZGlzdGFuY2UgPj0gLTUwMDApICU+JSAKICBnZ3Bsb3QoKSArCiAgZ2VvbV92aW9saW4oYWVzKHggPSBiaW4sIHkgPSBDb3JyZWxhdGlvbiksIGZpbGwgPSAiIzY5YjNhMiIsIGFscGhhID0gLjYsIHNjYWxlID0gIndpZHRoIikgKwogIGdlb21fYm94cGxvdChhZXMoeCA9IGJpbiwgeSA9IENvcnJlbGF0aW9uKSwgYWxwaGEgPSAwKSArCiAgbGFicyh0aXRsZSA9ICJEaXN0YW5jZSAtNWtiIHVwc3RyZWFtIG9mIFRTUywgMTAwYnAgYmlucyIsCiAgICAgICB4ID0gIkRpc3RhbmNlIC01a2IgdXBzdHJlYW0gb2YgVFNTIiwgeSA9ICJDb3JyZWxhdGlvbiIpICsgCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZT0iU2V0MyIpICsKICBDVVNUT01fVEhFTUUKCiAgCiAgCmdnc2F2ZSgiS2F0aGkvcGxvdHMvZGlzdGFuY2Vfd2l0aGluX3Byb21vdGVyLnBkZiIpCmBgYAoKCgoKIyBUQUQgYm91bmRhcmllcwoKSW4gY2FzZSBIaS1DIGRhdGEgYXJlIGF2YWlsYWJsZSwgVEFEIGJvdW5kYXJpZXMgY291bGQgYWlkIGluIGZpbmRpbmcgCnBlYWstdG8tZ2VuZSBsaW5rcy4gU2V0dGluZyBhIGRpc3RhbmNlIGRlY2F5IHJhdGUgdG8gdGhlIHNhbWUgdmFsdWUKZm9yIGFsbCBnZW5lcyBhbmQgY2VsbHR5cGVzLCBkb2VzIG5vdCBnaXZlIGNyZWRpdCB0byB0aGUgYmlvbG9naWNhbCB2YXJpYWJpbGl0eSBhc3NvY2lhdGVkIHdpdGggZ2VuZSByZWd1bGF0aW9uLiBJbiBbQFp1aW4yMDIyXSBpdCBoYXMgYmVlbgpzaG93biBleHBlcmltZW50YWxseSwgdGhhdCBpbnRlcmFjdGlvbnMgYmV0d2VlbiByZWd1bGF0b3J5IGVsZW1lbnRzIApkZWNheSBleHBvbmVudGlhbGx5IHdpdGhpbiBUQUQgYm91bmRhcmllcyBhbmQgYWxtb3N0IGRpc2FwcGVhciBjb21wbGV0ZWx5IGJleW9uZCBUQUQgYm91bmRhcmllcy4gSGVyZSwgSSByZXN0cmljdGVkIHRoZSBwZWFrLXRvLWdlbmUgbGlua3MgaWRlbnRpZmllZCBieSBBcmNoUiB0byB3aXRoaW4gVEFEIGJvdW5kYXJpZXMgYW5kIGNvbXB1dGVkIGdlbmUgYWN0aXZpdHkgc2NvcmVzIGFnYWluLgoKYGBge3J9ClRIRU1FX0xPTkcgPC0gICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLAogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSksICMgY2hhbmdlIHNpemUgb2YgYXhpcyB0aXRsZQogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTUpLAogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIHNpemUgPSAyMCksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIk5vbmUiLCAKICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9saW5lKGNvbG91ciA9ICJncmV5IiksICAgIyBNYWpvciBncmlkIGxpbmVzCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIndoaXRlIiwgY29sb3VyID0gImJsYWNrIiksCiAgICAgICAgYXNwZWN0LnJhdGlvID0gMC4yKQpgYGAKCgpgYGB7ciwgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTZ9CnRhZF9ib3VuZGFyaWVzIDwtIGFzLmRhdGEuZnJhbWUocmVhZC50YWJsZSgiS2F0aGkvdGFkX2U3NS5iZWQiLCBoZWFkZXIgPSBGQUxTRSwgc2VwID0gIlx0Iiwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFLCBxdW90ZSA9ICIiKSkKdGFkX2JvdW5kYXJpZXMgPC0gdGFkX2JvdW5kYXJpZXMgJT4lIAogIHJlbmFtZShzZXFuYW1lcyA9IFYxLCBzdGFydCA9IFYyLCBlbmQgPSBWMykgJT4lIAogIEdSYW5nZXMoKQoKcDEgPC0gZ2dwbG90KCkgKyBnZW9tX2hpc3RvZ3JhbShhZXMoeCA9IHdpZHRoKGdlbmVfYW5ubyAlPiUgR1JhbmdlcygpKSksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiaW5zID0gMjAwKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gbWVkaWFuKHdpZHRoKGdlbmVfYW5ubyAlPiUgR1JhbmdlcygpKSksIAogICAgICAgICAgICAgY29sb3IgPSAib3JhbmdlIikgKwogIGxhYnModGl0bGUgPSBwYXN0ZTAoIkRpc3RyaWJ1dGlvbiBvZiBnZW5lIHNpemUsIG1lZGlhbiBzaXplID0gIiwKICAgICAgICAgICAgICAgICAgICAgIG1lZGlhbih3aWR0aChnZW5lX2Fubm8gJT4lIEdSYW5nZXMoKSkpLCAiIGJwIiksCiAgICAgICB4ID0gImdlbmUgc2l6ZSAoYnApIikgKwogIFRIRU1FX0xPTkcKCnAyIDwtIGdncGxvdCgpICsgZ2VvbV9oaXN0b2dyYW0oYWVzKHggPSB3aWR0aCh0YWRfYm91bmRhcmllcykpLCBiaW5zID0gMjAwKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gbWVkaWFuKHdpZHRoKHRhZF9ib3VuZGFyaWVzKSksIGNvbG9yID0gIm9yYW5nZSIpICsKICBsYWJzKHRpdGxlID0gcGFzdGUwKCJEaXN0cmlidXRpb24gb2YgVEFEIGJvdW5kYXJ5IHNpemUsIG1lZGlhbiBzaXplID0gIiwKICAgICAgIG1lZGlhbih3aWR0aCh0YWRfYm91bmRhcmllcykpLCAiIGJwIiksCiAgICAgIHggPSAiVEFEIGJvdW5kYXJ5IHNpemUgKGJwKSIpICsKICBUSEVNRV9MT05HCgpjb3dwbG90OjpwbG90X2dyaWQocDEsIHAyLCBuY29sID0gMSkKYGBgCgpXaGF0IGlzIHRoZSBkaXN0cmlidXRpb24gb2YgcGVha3MgYW5kIGdlbmVzIHdpdGhpbiBUQUQgYm91bmRhcmllcz8KCmBgYHtyLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9Nn0KZ2VuZV9hbm5vIDwtIEdFTkVfQU5OTwoKIyBjcmVhdGUgZ2VuZSBhbm5vdGF0aW9ucyB3aXRoIHN0YXJ0IGNvb3JkaW5hdGUgb2YgZWFjaCBnZW5lCiMgc3Vic2V0IHRvIGNvbnRhaW4gb25seSBnZW5lcyB3aGljaCBhcmUgaW5jbHVkZWQgaW4gb3VyIHBlYWsyZ2VuZSBtYXRyaXgKZ2VuZV9hbm5vIDwtIGdlbmVfYW5ubyAlPiUgYXMuZGF0YS5mcmFtZSgpICU+JQogIG11dGF0ZShpZHhSTkEgPSBzZXEobnJvdyguKSkpICU+JSAKICBkcGx5cjo6ZmlsdGVyKG5hbWUgJWluJSByb3duYW1lcyhwMmdfbWF0X3N1YikpICU+JQogIG11dGF0ZShzdHJhbmQgPSBpZmVsc2Uoc3RyYW5kID09IDEsICIrIiwgIi0iKSkgJT4lCiAgbXV0YXRlKHN0YXJ0X2Nvb3JkID0gaWZlbHNlKHN0cmFuZCA9PSAiKyIsIHN0YXJ0LCBlbmQpKSAlPiUgCiAgcmVuYW1lKGdlbmUgPSBuYW1lKSAjJT4lIEdSYW5nZXMoKQoKCiMgc3Vic2V0IGF0YWMgZ3JhbmdlcyAmIGdldCBtaWRkbGUgb2YgZWFjaCBwZWFrCnBvc19hdGFjX2dyYW5nZXMgPC0gYXRhY19ncmFuZ2VzICAlPiUgCiAgYXMuZGF0YS5mcmFtZSgpICU+JQogIG11dGF0ZShpZHhBVEFDID0gc2VxKG5yb3coLikpKSAlPiUgCiAgIyBncm91cF9ieShzZXFuYW1lcykgJT4lCiAgIyBtdXRhdGUoaWR4ID0gc2VxX2Fsb25nKHNlcW5hbWVzKSkgJT4lIAogICMgdW5ncm91cCAlPiUKICAjdGlkeXI6OnVuaXRlKGNocl9pZHgsIHNlcW5hbWVzLCBpZHgsIHJlbW92ZSA9IEZBTFNFLCBzZXAgPSAiXyIpICU+JSAKICBkcGx5cjo6ZmlsdGVyKGlkeEFUQUMgJWluJSBjb2xuYW1lcyhwMmdfbWF0X3N1YikpICU+JSAKICBtdXRhdGUobWlkZGxlID0gc3RhcnQgKyAzMDApICMlPiUgR1JhbmdlcygpIAoKI1RPRE86IEZpbHRlciBmb3IgZ2VuZXMhCnN0b3BpZm5vdChsZW5ndGgodW5pcXVlKGxpbmtzJGlkeEFUQUMpKSA9PSBkaW0ocG9zX2F0YWNfZ3JhbmdlcylbWzFdXSkKc3RvcGlmbm90KGxlbmd0aCh1bmlxdWUobGlua3MkaWR4Uk5BKSkgPT0gZGltKGdlbmVfYW5ubylbWzFdXSkKI3AyZ19maWx0IDwtIHAyZ19vcmlnaW5hbCAlPiUgYXMuZGF0YS5mcmFtZSgpICU+JSBmaWx0ZXIoZ2VuZSAlaW4lIHJvd25hbWVzKHAyZ19tYXQpKQoKCiAgIyBmaW5kIG92ZXJsYXBwaW5nIHBlYWtzIGFuZCBnZW5lIHdpbmRvdyBpbiBjaHJvbW9zb21lLWF3YXJlIGZhc2hpb24KdGFkX292ZXJsYXBzX2dlbmVzIDwtIHN1cHByZXNzV2FybmluZ3MoZmluZE92ZXJsYXBzKGdlbmVfYW5ubyAlPiUgR1JhbmdlcygpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRhZF9ib3VuZGFyaWVzKSkKCnAxIDwtIHRhZF9vdmVybGFwc19nZW5lcyAlPiUgYXMuZGF0YS5mcmFtZSgpICU+JQogIGdyb3VwX2J5KHN1YmplY3RIaXRzKSAlPiUKICBzdW1tYXJpc2UobiA9IG4oKSkgJT4lIAogIGdncGxvdCgpICsgZ2VvbV9oaXN0b2dyYW0oYWVzKHggPSBuKSwgYmlucyA9IDEwMCkgKwogIGxhYnModGl0bGUgPSAiTnVtYmVyIG9mIGhpZ2hseSB2YXJpYWJsZSBnZW5lcyB3aXRoaW4gYSB0YWQgYm91bmRhcnkiLAogICAgICAgeCA9ICJudW1iZXIgb2YgZ2VuZXMvdGFkIGJvdW5kYXJ5IikgKwogIENPUlJfVEhFTUUKCnRhZF9vdmVybGFwc19wZWFrcyA8LSBzdXBwcmVzc1dhcm5pbmdzKGZpbmRPdmVybGFwcyhwb3NfYXRhY19ncmFuZ2VzICU+JSBHUmFuZ2VzKCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGFkX2JvdW5kYXJpZXMpKQoKCnAyIDwtIHRhZF9vdmVybGFwc19wZWFrcyAlPiUgYXMuZGF0YS5mcmFtZSgpICU+JQogIGdyb3VwX2J5KHN1YmplY3RIaXRzKSAlPiUKICBzdW1tYXJpc2UobiA9IG4oKSkgJT4lIAogIGdncGxvdCgpICsgZ2VvbV9oaXN0b2dyYW0oYWVzKHggPSBuKSwgYmlucyA9IDEwMCkgKwogIGxhYnModGl0bGUgPSAiTnVtYmVyIG9mIHBlYWtzIHdpdGhpbiBhIHRhZCBib3VuZGFyeSIsCiAgICAgICB4ID0gIm51bWJlciBvZiBwZWFrcy90YWQgYm91bmRhcnkiKSArCiAgQ09SUl9USEVNRQoKCmNvd3Bsb3Q6OnBsb3RfZ3JpZChwMSwgcDIsIG5jb2wgPSAyKQpgYGAKCkhvdyBtYW55IHAyZyBsaW5rcyBhcmUgd2l0aGluIHRhZCBib3VuZGFyaWVzPwoKUGVhay10by1nZW5lIGxpbmtzIGNvbnNpZGVyZWQgaW4gYWJvdmUgY29tcHV0YXRpb25zCgpBbGwgcGVhay10by1nZW5lIGxpbmtzCgpgYGAje3IsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD01fQpybShwZWFrcykKZ2MocmVzZXQgPSBUUlVFKQoKcDJnX3BvcyA8LSBwMmcgJT4lIGFzLmRhdGEuZnJhbWUoKSAlPiUgZmlsdGVyKENvcnJlbGF0aW9uID4gMCkgJT4lCiAgdW5pdGUobGluaywgaWR4Uk5BLCBpZHhBVEFDLCBzZXAgPSAiJSIsIHJlbW92ZSA9IEZBTFNFKQoKZ2VuZV9hbm5vX2FsbCA8LSByb3dEYXRhKGdlbmVfZXhwcikgJT4lIGFzLmRhdGEuZnJhbWUoKSAlPiUKICBtdXRhdGUoaWR4Uk5BID0gc2VxKG5yb3coLikpKSAlPiUgCiAgZmlsdGVyKGlkeFJOQSAlaW4lIHAyZ19wb3MkaWR4Uk5BKSAlPiUKICBtdXRhdGUoc3RyYW5kID0gaWZlbHNlKHN0cmFuZCA9PSAxLCAiKyIsICItIikpICU+JQogIG11dGF0ZShzdGFydF9jb29yZCA9IGlmZWxzZShzdHJhbmQgPT0gIisiLCBzdGFydCwgZW5kKSkgJT4lIAogIHJlbmFtZShnZW5lID0gbmFtZSkgIyU+JSBHUmFuZ2VzKCkKCiMgc3Vic2V0IGF0YWMgZ3JhbmdlcyAmIGdldCBtaWRkbGUgb2YgZWFjaCBwZWFrCnBvc19hdGFjX2dyYW5nZXNfYWxsIDwtIG1ldGFkYXRhKHAyZylbWzFdXSAgJT4lIAogIGFzLmRhdGEuZnJhbWUoKSAlPiUKICBtdXRhdGUoaWR4QVRBQyA9IHNlcShucm93KC4pKSkgJT4lIAogICMgZ3JvdXBfYnkoc2VxbmFtZXMpICU+JQogICMgbXV0YXRlKGlkeCA9IHNlcV9hbG9uZyhzZXFuYW1lcykpICU+JSAKICAjIHVuZ3JvdXAgJT4lCiAgI3RpZHlyOjp1bml0ZShjaHJfaWR4LCBzZXFuYW1lcywgaWR4LCByZW1vdmUgPSBGQUxTRSwgc2VwID0gIl8iKSAlPiUgCiAgZmlsdGVyKGlkeEFUQUMgJWluJSBwMmdfcG9zJGlkeEFUQUMpICU+JSAKICBtdXRhdGUobWlkZGxlID0gc3RhcnQgKyAzMDApICMlPiUgR1JhbmdlcygpIAoKCgojIGNvbWJpbmUgdGhlIHRocmVlIGRhdGFmcmFtZXMKcDJnX2pvaW5fYWxsIDwtIGxlZnRfam9pbihwMmdfcG9zLCBhcy5kYXRhLmZyYW1lKHBvc19hdGFjX2dyYW5nZXNfYWxsKSwKICAgICAgICAgICAgICAgICAgICAgIGJ5ID0gImlkeEFUQUMiKQpwMmdfam9pbl9hbGwgPC0gbGVmdF9qb2luKHAyZ19qb2luX2FsbCwgYXMuZGF0YS5mcmFtZShnZW5lX2Fubm9fYWxsKSwKICAgICAgICAgICAgICAgICAgICAgIGJ5ID0gImlkeFJOQSIsIHN1ZmZpeCA9IGMoIi5hdGFjIiwgIi5ybmEiKSkKCgpwMmdfam9pbl9hbGwgPC0gcDJnX2pvaW5fYWxsICU+JSAKICBtdXRhdGUoZGlzdGFuY2UgPSBhYnMoc3RhcnRfY29vcmQgLSBtaWRkbGUpKQoKCgogICMgZmluZCBvdmVybGFwcGluZyBwZWFrcyBhbmQgZ2VuZSB3aW5kb3cgaW4gY2hyb21vc29tZS1hd2FyZSBmYXNoaW9uCnRhZF9vdmVybGFwc19nZW5lcyA8LSBzdXBwcmVzc1dhcm5pbmdzKGZpbmRPdmVybGFwcyhnZW5lX2Fubm9fYWxsICU+JSBHUmFuZ2VzKCksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGFkX2JvdW5kYXJpZXMpKQoKIyBnZXQgZ2VuZXMgd2hpY2ggYXJlIG5vdCBmb3VuZCB3aXRoaW4gdHdvIFRBRCBib3VuZGFyaWVzLCBidXQgb25seSB3aXRoaW4gb25lCndpdGhpbl9nZW5lcyA8LSAodGFkX292ZXJsYXBzX2dlbmVzICU+JSAKYXMuZGF0YS5mcmFtZSgpICU+JSAKZ3JvdXBfYnkocXVlcnlIaXRzKSAlPiUKc3VtbWFyaXNlKG4gPSBuKCkpICU+JSB1bmdyb3VwKCkgJT4lCmZpbHRlcihuIDwgMikpJHF1ZXJ5SGl0cwoKcHJpbnQocGFzdGUwKCJPdXQgb2YgIiwgbnJvdyhnZW5lX2Fubm9fYWxsKSwgIiBnZW5lcywgIiwgbGVuZ3RoKHVuaXF1ZShxdWVyeUhpdHModGFkX292ZXJsYXBzX2dlbmVzKSkpLCAiIGdlbmVzIGFyZSB3aXRoaW4gVEFEIGJvdW5kYXJpZXMuIFNvbWUgb2YgdGhlc2UgZ2VuZXMgZXZlbiBzcGFuIGFjcm9zcyBUQUQgYm91ZG5hcmllcywgbmFtZWx5ICIsIGFicyhsZW5ndGgod2l0aGluX2dlbmVzKSAtIGxlbmd0aCh1bmlxdWUocXVlcnlIaXRzKHRhZF9vdmVybGFwc19nZW5lcykpKSksICIuIikpCgojIFdlIG9ubHkga2VlcCBnZW5lcyB3aXRoaW4gYm91bmRhcmllcywgYnV0IG5vdCBnZW5lcyBjcm9zc2luZyBib3VuZGFyaWVzCnRhZF9vdmVybGFwc19nZW5lcyA8LSB0YWRfb3ZlcmxhcHNfZ2VuZXMgJT4lIGFzLmRhdGEuZnJhbWUgJT4lIAogIGZpbHRlcihxdWVyeUhpdHMgJWluJSB3aXRoaW5fZ2VuZXMpICMlPiUgUzRWZWN0b3JzOjphcygpCgojIGdldCBwZWFrcyBvdmVybGFwcGluZyB3aXRoIHRhZCBib3VuZGFyaWVzCnRhZF9vdmVybGFwc19wZWFrcyA8LSBzdXBwcmVzc1dhcm5pbmdzKGZpbmRPdmVybGFwcyhwb3NfYXRhY19ncmFuZ2VzX2FsbCAlPiUgR1JhbmdlcygpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0YWRfYm91bmRhcmllcykpCgojIGZpbHRlciBmb3IgcGVha3Mgb3ZlcmxhcHBpbmcgdGFkIGJvdW5kYXJpZXMgd2hpY2ggYWxzbyBjb250YWluIGdlbmVzCnRhZF9vdmVybGFwc19wZWFrcyA8LSB0YWRfb3ZlcmxhcHNfcGVha3MgJT4lIGFzLmRhdGEuZnJhbWUoKSAlPiUgCiAgZmlsdGVyKHN1YmplY3RIaXRzICVpbiUgdGFkX292ZXJsYXBzX2dlbmVzJHN1YmplY3RIaXRzKQoKIyBjb21iaW5lIHRhZCBib3VuZGFyaWVzIHdoaWNoIGNvbnRhaW4gZ2VuZXMgYW5kIHBlYWtzCnRhZF9jb21iaW5lIDwtIGxlZnRfam9pbih0YWRfb3ZlcmxhcHNfZ2VuZXMsIHRhZF9vdmVybGFwc19wZWFrcywgCiAgICAgICAgICAgICAgICAgICAgICAgICBjb3B5ID0gVFJVRSwgYnkgPSAic3ViamVjdEhpdHMiLCBzdWZmaXggPSBjKCIuZ2VuZSIsICIucGVhayIpKSAlPiUKICB1bml0ZShsaW5rLCBxdWVyeUhpdHMuZ2VuZSwgcXVlcnlIaXRzLnBlYWssIHNlcCA9ICIlIiwgcmVtb3ZlID0gRkFMU0UpCgoKZ2VuZXMgPC0gZ2VuZV9hbm5vX2FsbFt0YWRfY29tYmluZSRxdWVyeUhpdHMuZ2VuZSwgXSAlPiUKICBtdXRhdGUodGFkX2luZGV4ID0gdGFkX2NvbWJpbmUkc3ViamVjdEhpdHMpCgpwZWFrX2NvbGwgPC0gcG9zX2F0YWNfZ3Jhbmdlc19hbGxbdGFkX2NvbWJpbmUkcXVlcnlIaXRzLnBlYWssIF0gJT4lIAogIG11dGF0ZSh0YWRfaW5kZXggPSB0YWRfY29tYmluZSRzdWJqZWN0SGl0cykKCmdlbmVfcGVha190YWRfZGYgPC0gbGVmdF9qb2luKGdlbmVzLCBwZWFrX2NvbGwsIGJ5ID0gInRhZF9pbmRleCIsIHN1ZmZpYyA9IGMoIi5nZW5lIiwgIi5wZWFrIikpICU+JSAgdW5pdGUocGVha19nZW5lX3RhZCwgZ2VuZSwgaWR4QVRBQywgc2VwID0gIiMiLCByZW1vdmUgPSBGQUxTRSkKCiMjIyBzb21lIHBsb3RzCnAxIDwtICh0YWRfb3ZlcmxhcHNfcGVha3MgICU+JSBhcy5kYXRhLmZyYW1lKCkgJT4lIAogICAgICAgZ3JvdXBfYnkoc3ViamVjdEhpdHMpICU+JSAjIGdlbmUgcmVnaW9uCiAgICAgICBzdW1tYXJpemUobiA9IG4oKSkgJT4lICMgZ2V0IG51bWJlciBvZiBwZWFrcyBvdmVybGFwcGluZyB3aXRoIGEgZ2VuZSByZWdpb24KICAgICAgIGdncGxvdCgpICsgZ2VvbV9oaXN0b2dyYW0oYWVzKHggPSBuKSwgYmlucyA9IDEwMCwgZmlsbD0iIzY5YjNhMiIpICsKICAgICAgIGxhYnModGl0bGUgPSAiTnVtYmVyIG9mIHBlYWtzIHBlciB0YWQgYm91bmRhcnksIHBvc2l0aXZlIHAyZyBsaW5rcyIsCiAgICAgICAgICAgeCA9ICJudW1iZXIgb2YgcGVha3MiKSkKCnAyIDwtICh0YWRfb3ZlcmxhcHNfZ2VuZXMgICU+JSBhcy5kYXRhLmZyYW1lKCkgJT4lIAogICAgIGdyb3VwX2J5KHN1YmplY3RIaXRzKSAlPiUgIyBnZW5lIHJlZ2lvbgogICAgIHN1bW1hcml6ZShuID0gbigpKSAlPiUgIyBnZXQgbnVtYmVyIG9mIHBlYWtzIG92ZXJsYXBwaW5nIHdpdGggYSBnZW5lIHJlZ2lvbgogICAgIGdncGxvdCgpICsgZ2VvbV9oaXN0b2dyYW0oYWVzKHggPSBuKSwgYmlucyA9IDEwMCwgZmlsbD0iIzY5YjNhMiIpICsKICAgICBsYWJzKHRpdGxlID0gIk51bWJlciBvZiBnZW5lcyBwZXIgdGFkIGJvdW5kYXJ5LCBwb3NpdGl2ZSBwMmcgbGlua3MiLAogICAgICAgICB4ID0gIm51bWJlciBvZiBnZW5lcyIpKQoKcHJpbnQoY293cGxvdDo6cGxvdF9ncmlkKHAxLCBwMiwgbmNvbCA9IDIpKQoKCgpwcmludChwYXN0ZTAoIlRoZSBudW1iZXIgb2YgcG9zaXRpdmUgcGVhay10by1nZW5lIGxpbmtzIGlzOiAiLCBsZW5ndGgocDJnX3BvcyRsaW5rKSkpCnByaW50KHBhc3RlMCggIlRoZSBudW1iZXIgb2YgcG9zaXRpdmUgcGVhay10by1nZW5lIGxpbmtzIHdpdGhpbiBUQUQgYm91bmRhcmllcyBpczogIiwgbGVuZ3RoKHRhZF9jb21iaW5lJGxpbmspKSkKCnByaW50KHBhc3RlMCgiVGhlIG51bWJlciBvZiBwb3NpdGl2ZSBwZWFrLXRvLWdlbmUgbGlua3Mgb3V0c2lkZSBUQUQgYm91bmRhcmllcyBpczogIiwgbGVuZ3RoKHAyZ19wb3MkbGluaykgLSBsZW5ndGgodGFkX2NvbWJpbmUkbGluaykpKQoKCnByaW50KHBhc3RlMCgiVGhlIHByb3BvcnRpb24gb2YgcGVhay10by1nZW5lIGxpbmtzIHdpdGhpbiBUQUQgYm91bmRhcmllcyBvdXQgb2YgYWxsIAogICAgICAgICAgICAgcG9zaXRpdmUgcGVhay10by1nZW5lIGxpbmtzIGFjcm9zcyB0aGUgZW50aXJlIGNocm9tb3NvbWUgaXMgIiwKICAgICAgICAgICAgIHJvdW5kKGxlbmd0aCh0YWRfY29tYmluZSRsaW5rKSAvIGxlbmd0aChwMmdfcG9zJGxpbmspLCA1KSkpCgoKCiNnZ3Bsb3QoKSArIGdlb21fcG9pbnQoYWVzKHggPSBwMmdfcG9zJGlkeEFUQUMsIHkgPSBwMmdfcG9zJGlkeFJOQSkpCgoKYGBgCgojIyBEaXN0YW5jZSB2cy4gQ29ycmVsYXRpb24KCkhlcmUgSSB2aXN1YWxpemUgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGRpc3RhbmNlIGJldHdlZW4gcGVha3MgYW5kIGdlbmVzCmFuZCB0aGVpciByZXNwZWN0aXZlIGNvcnJlbGF0aW9uIHZhbHVlcyB1c2luZyBhbGwgcG9zaXRpdmUgbGlua3Mgb2J0YWluZWQgCnVzaW5nIEFyY2hSIAoKYGBgI3tyfQpwMmdfam9pbl9hbGwgJT4lICAKICBtdXRhdGUoYmluPWN1dF93aWR0aChkaXN0YW5jZSwgd2lkdGg9MTAwMDAwLCBib3VuZGFyeT0wKSkgJT4lCiAgZmlsdGVyKGRpc3RhbmNlIDwgMTAwMDAwMDApICU+JSAKICBnZ3Bsb3QoKSArCiAgZ2VvbV9ib3hwbG90KGFlcyh4ID0gYmluLCB5ID0gQ29ycmVsYXRpb24pLCBmaWxsPSIjNjliM2EyIikgKwogICNnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgID0gMjUwMDAwLCBjb2xvciA9ICJyZWQiKSArCiAgbGFicyh0aXRsZSA9ICJSZWxhdGlvbnNoaXAgYmV0d2VlbiBkaXN0YW5jZSBhbmQgY29ycmVsYXRpb24gb2YgcDJnIGxpbmtzLCAxMDBrYiBiaW5zIiwKICAgICAgIHggPSAiRGlzdGFuY2UgYmV0d2VlbiBwZWFrcyBhbmQgZ2VuZXMgd2l0aGluIDI1MGtiIiwgeSA9ICJDb3JyZWxhdGlvbiIpICsgCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjUsIGhqdXN0PTEpKQoKYGBgCgoKYGBge3IsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD02fQoKY29sUGFsZXR0ZV9jZWxsdHlwZXMgPSBjKCcjNTMyQzhBJywKICcjYzE5ZjcwJywKICcjZjlkZWNmJywKICcjYzlhOTk3JywKICcjQjUxRDhEJywKICcjM0Y4NEFBJywKICcjOWU2NzYyJywKICcjMzU0RTIzJywKICcjRjM5N0MwJywKICcjZmY4OTFjJywKICcjNjM1NTQ3JywKICcjQzcyMjI4JywKICcjZjc5MDgzJywKICcjRUY0RTIyJywKICcjOTg5ODk4JywKICcjN0Y2ODc0JywKICcjODg3MGFkJywKICcjNjQ3YTRmJywKICcjRUY1QTlEJywKICcjRkJCRTkyJywKICcjMTM5OTkyJywKICcjY2M3ODE4JywKICcjREZDREU0JywKICcjOEVDNzkyJywKICcjQzU5NEJGJywKICcjQzNDMzg4JywKICcjMEY0QTlDJywKICcjRkFDQjEyJywKICcjOERCNUNFJywKICcjMUExQTFBJywKICcjQzlFQkZCJywKICcjREFCRTk5JywKICcjNjVBODNFJywKICcjMDA1NTc5JywKICcjQ0RFMDg4JywKICcjZjdmNzllJywKICcjRjZCRkNCJykKCnRhZF9ib3VuZGFyaWVzICU+JSBhcy5kYXRhLmZyYW1lKCkgJT4lIGdyb3VwX2J5KHNlcW5hbWVzKSAlPiUgCiAgc3VtbWFyaXNlKG4gPSBuKCkpICU+JSB1bmdyb3VwKCkgJT4lICAKICBnZ3Bsb3QoKSArIGdlb21fY29sKGFlcyh4ID0gc2VxbmFtZXMsIHkgPSBuKSwgIGNvbG9yID0gImJsYWNrIiwgYWxwaGEgPSAuNikgKyMsIGZpbGwgPSBzZXFuYW1lcyksIGFscGhhID0gLjcpICsjLCBwb3NpdGlvbiA9ICJkb2RnZSIpCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIk5vbmUiKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY29sUGFsZXR0ZV9jZWxsdHlwZXMpICsKICBsYWJzKHkgPSAibnVtYmVyIG9mIHRhZCBib3VuZGFyaWVzIiwgeCA9ICJjaHJvbW9zb21lIikgKyAKICBDVVNUT01fVEhFTUUKCmBgYAoKClRPRE86IFNob3VsZCBJIGFsc28gcmVtb3ZlIHBlYWtzIHdoaWNoIGFyZSBhY3Jvc3MgVEFEIGJvdW5kYXJpZXM/CgpgYGB7ciwgZmlnLndpZHRoPTE1LCBmaWcuaGVpZ2h0PTEwfQojIEFzIGlucHV0IGZvciB0aGlzIGZ1bmN0aW9uIGl0IGlzIGJlc3QgdG8gdXNlIG9ubHkgdGhlIG1vc3QgaGlnaGx5IHZhcmlhYmxlIGdlbmVzCnRhZF9ib3VuZGFyaWVzX3AyZ19zY29yZXMgPC0gZnVuY3Rpb24ocDJnX21hdF9zdWIsIHBlYWtfbWF0LCBsaW5rcywgcDJnX29yaWdpbmFsLCBnZW5lX2Fubm8sIHRhZF9ib3VuZGFyaWVzKXsKICBhdGFjX2dyYW5nZXMgPC0gbWV0YWRhdGEocDJnX29yaWdpbmFsKVtbMV1dCiAgI3JuYV9ncmFuZ2VzIDwtIG1ldGFkYXRhKHAyZ19vcmlnaW5hbClbWzJdXQogIGdlbmVfYW5ub19vcmlnaW5hbCA8LSBnZW5lX2Fubm8KICAKICAjIGNyZWF0ZSBnZW5lIGFubm90YXRpb25zIHdpdGggc3RhcnQgY29vcmRpbmF0ZSBvZiBlYWNoIGdlbmUKICAjIHN1YnNldCB0byBjb250YWluIG9ubHkgZ2VuZXMgd2hpY2ggYXJlIGluY2x1ZGVkIGluIG91ciBwZWFrMmdlbmUgbWF0cml4CiAgZ2VuZV9hbm5vIDwtIGdlbmVfYW5ubyAlPiUgYXMuZGF0YS5mcmFtZSgpICU+JQogICAgbXV0YXRlKGlkeFJOQSA9IHNlcShucm93KC4pKSkgJT4lIAogICAgZHBseXI6OmZpbHRlcihuYW1lICVpbiUgcm93bmFtZXMocDJnX21hdF9zdWIpKSAlPiUKICAgIG11dGF0ZShzdHJhbmQgPSBpZmVsc2Uoc3RyYW5kID09IDEsICIrIiwgIi0iKSkgJT4lCiAgICBtdXRhdGUoc3RhcnRfY29vcmQgPSBpZmVsc2Uoc3RyYW5kID09ICIrIiwgc3RhcnQsIGVuZCkpICU+JSAKICAgIHJlbmFtZShnZW5lID0gbmFtZSkgIyU+JSBHUmFuZ2VzKCkKCgogICMgc3Vic2V0IGF0YWMgZ3JhbmdlcyAmIGdldCBtaWRkbGUgb2YgZWFjaCBwZWFrCiAgcG9zX2F0YWNfZ3JhbmdlcyA8LSBhdGFjX2dyYW5nZXMgICU+JSAKICAgIGFzLmRhdGEuZnJhbWUoKSAlPiUKICAgIG11dGF0ZShpZHhBVEFDID0gc2VxKG5yb3coLikpKSAlPiUgCiAgICAjIGdyb3VwX2J5KHNlcW5hbWVzKSAlPiUKICAgICMgbXV0YXRlKGlkeCA9IHNlcV9hbG9uZyhzZXFuYW1lcykpICU+JSAKICAgICMgdW5ncm91cCAlPiUKICAgICN0aWR5cjo6dW5pdGUoY2hyX2lkeCwgc2VxbmFtZXMsIGlkeCwgcmVtb3ZlID0gRkFMU0UsIHNlcCA9ICJfIikgJT4lIAogICAgZHBseXI6OmZpbHRlcihpZHhBVEFDICVpbiUgY29sbmFtZXMocDJnX21hdF9zdWIpKSAlPiUgCiAgICBtdXRhdGUobWlkZGxlID0gc3RhcnQgKyAzMDApICMlPiUgR1JhbmdlcygpIAogIAogICNUT0RPOiBGaWx0ZXIgZm9yIGdlbmVzIQogIHN0b3BpZm5vdChsZW5ndGgodW5pcXVlKGxpbmtzJGlkeEFUQUMpKSA9PSBkaW0ocG9zX2F0YWNfZ3JhbmdlcylbWzFdXSkKICBzdG9waWZub3QobGVuZ3RoKHVuaXF1ZShsaW5rcyRpZHhSTkEpKSA9PSBkaW0oZ2VuZV9hbm5vKVtbMV1dKQogICNwMmdfZmlsdCA8LSBwMmdfb3JpZ2luYWwgJT4lIGFzLmRhdGEuZnJhbWUoKSAlPiUgZmlsdGVyKGdlbmUgJWluJSByb3duYW1lcyhwMmdfbWF0KSkKICAKICAKICAgICMgZmluZCBvdmVybGFwcGluZyBwZWFrcyBhbmQgZ2VuZSB3aW5kb3cgaW4gY2hyb21vc29tZS1hd2FyZSBmYXNoaW9uCiAgdGFkX292ZXJsYXBzX2dlbmVzIDwtIHN1cHByZXNzV2FybmluZ3MoZmluZE92ZXJsYXBzKGdlbmVfYW5ubyAlPiUgR1JhbmdlcygpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGFkX2JvdW5kYXJpZXMpKQogIAogICMgZ2V0IGdlbmVzIHdoaWNoIGFyZSBub3QgZm91bmQgd2l0aGluIHR3byBUQUQgYm91bmRhcmllcywgYnV0IG9ubHkgd2l0aGluIG9uZQogIHdpdGhpbl9nZW5lcyA8LSAodGFkX292ZXJsYXBzX2dlbmVzICU+JSAKICBhcy5kYXRhLmZyYW1lKCkgJT4lIAogIGdyb3VwX2J5KHF1ZXJ5SGl0cykgJT4lCiAgc3VtbWFyaXNlKG4gPSBuKCkpICU+JSB1bmdyb3VwKCkgJT4lCiAgZHBseXI6OmZpbHRlcihuIDwgMikpJHF1ZXJ5SGl0cwoKICBwcmludChwYXN0ZTAoIk91dCBvZiAiLCBucm93KGdlbmVfYW5ubyksICIgZ2VuZXMsICIsIGxlbmd0aCh1bmlxdWUocXVlcnlIaXRzKHRhZF9vdmVybGFwc19nZW5lcykpKSwgIiBnZW5lcyBhcmUgd2l0aGluIFRBRCBib3VuZGFyaWVzLiBTb21lIG9mIHRoZXNlIGdlbmVzIGV2ZW4gc3BhbiBhY3Jvc3MgVEFEIGJvdWRuYXJpZXMsIG5hbWVseSAiLCBsZW5ndGgod2l0aGluX2dlbmVzKSwgIi4iKSkKICAKICAjIFdlIG9ubHkga2VlcCBnZW5lcyB3aXRoaW4gYm91bmRhcmllcywgYnV0IG5vdCBnZW5lcyBjcm9zc2luZyBib3VuZGFyaWVzCiAgdGFkX292ZXJsYXBzX2dlbmVzIDwtIHRhZF9vdmVybGFwc19nZW5lcyAlPiUgYXMuZGF0YS5mcmFtZSAlPiUgCiAgICBkcGx5cjo6ZmlsdGVyKHF1ZXJ5SGl0cyAlaW4lIHdpdGhpbl9nZW5lcykgIyU+JSBTNFZlY3RvcnM6OmFzKCkKICAKICAjIGdldCBwZWFrcyBvdmVybGFwcGluZyB3aXRoIHRhZCBib3VuZGFyaWVzCiAgdGFkX292ZXJsYXBzX3BlYWtzIDwtIHN1cHByZXNzV2FybmluZ3MoZmluZE92ZXJsYXBzKHBvc19hdGFjX2dyYW5nZXMgJT4lIEdSYW5nZXMoKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0YWRfYm91bmRhcmllcykpCiAgCiAgIyBmaWx0ZXIgZm9yIHBlYWtzIG92ZXJsYXBwaW5nIHRhZCBib3VuZGFyaWVzIHdoaWNoIGFsc28gY29udGFpbiBnZW5lcwogIHRhZF9vdmVybGFwc19wZWFrcyA8LSB0YWRfb3ZlcmxhcHNfcGVha3MgJT4lIGFzLmRhdGEuZnJhbWUoKSAlPiUgCiAgICBkcGx5cjo6ZmlsdGVyKHN1YmplY3RIaXRzICVpbiUgdGFkX292ZXJsYXBzX2dlbmVzJHN1YmplY3RIaXRzKQogIAogICMgY29tYmluZSB0YWQgYm91bmRhcmllcyB3aGljaCBjb250YWluIGdlbmVzIGFuZCBwZWFrcwogIHRhZF9jb21iaW5lIDwtIGxlZnRfam9pbih0YWRfb3ZlcmxhcHNfZ2VuZXMsIHRhZF9vdmVybGFwc19wZWFrcywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvcHkgPSBUUlVFLCBieSA9ICJzdWJqZWN0SGl0cyIsIHN1ZmZpeCA9IGMoIi5nZW5lIiwgIi5wZWFrIikpCiAgCiAgCiAgZ2VuZXMgPC0gZ2VuZV9hbm5vW3RhZF9jb21iaW5lJHF1ZXJ5SGl0cy5nZW5lLCBdICU+JQogICAgbXV0YXRlKHRhZF9pbmRleCA9IHRhZF9jb21iaW5lJHN1YmplY3RIaXRzKQogIAogIHBlYWtfY29sbCA8LSBwb3NfYXRhY19ncmFuZ2VzW3RhZF9jb21iaW5lJHF1ZXJ5SGl0cy5wZWFrLCBdICU+JSAKICAgIG11dGF0ZSh0YWRfaW5kZXggPSB0YWRfY29tYmluZSRzdWJqZWN0SGl0cykKICAKICBnZW5lX3BlYWtfdGFkX2RmIDwtIGxlZnRfam9pbihnZW5lcywgcGVha19jb2xsLCBieSA9ICJ0YWRfaW5kZXgiLCBzdWZmaWMgPSBjKCIuZ2VuZSIsICIucGVhayIpKSAlPiUgIHVuaXRlKHBlYWtfZ2VuZV90YWQsIGdlbmUsIGlkeEFUQUMsIHNlcCA9ICIjIiwgcmVtb3ZlID0gRkFMU0UpCgoKICAKICAjIyMgc29tZSBwbG90cwogIHAxIDwtICh0YWRfb3ZlcmxhcHNfcGVha3MgICU+JSBhcy5kYXRhLmZyYW1lKCkgJT4lIAogICAgICAgICBncm91cF9ieShzdWJqZWN0SGl0cykgJT4lICMgZ2VuZSByZWdpb24KICAgICAgICAgc3VtbWFyaXplKG4gPSBuKCkpICU+JSAjIGdldCBudW1iZXIgb2YgcGVha3Mgb3ZlcmxhcHBpbmcgd2l0aCBhIGdlbmUgcmVnaW9uCiAgICAgICAgIGdncGxvdCgpICsgZ2VvbV9oaXN0b2dyYW0oYWVzKHggPSBuKSwgYmlucyA9IDEwMCwgZmlsbD0iIzY5YjNhMiIpICsKICAgICAgICAgbGFicyh0aXRsZSA9ICJOdW1iZXIgb2YgcGVha3MgLyBUQUQgYm91bmRhcnkiLAogICAgICAgICAgICAgeCA9ICJudW1iZXIgb2YgcGVha3MiKSkgKwogICAgQ09SUl9USEVNRQogIAogIHAyIDwtICh0YWRfb3ZlcmxhcHNfZ2VuZXMgICU+JSBhcy5kYXRhLmZyYW1lKCkgJT4lIAogICAgICAgZ3JvdXBfYnkoc3ViamVjdEhpdHMpICU+JSAjIGdlbmUgcmVnaW9uCiAgICAgICBzdW1tYXJpemUobiA9IG4oKSkgJT4lICMgZ2V0IG51bWJlciBvZiBwZWFrcyBvdmVybGFwcGluZyB3aXRoIGEgZ2VuZSByZWdpb24KICAgICAgIGdncGxvdCgpICsgZ2VvbV9oaXN0b2dyYW0oYWVzKHggPSBuKSwgYmlucyA9IDEwMCwgZmlsbD0iIzY5YjNhMiIpICsKICAgICAgIGxhYnModGl0bGUgPSAiTnVtYmVyIG9mIGh2ZyBnZW5lcyAvIFRBRCBib3VuZGFyeSIsCiAgICAgICAgICAgeCA9ICJudW1iZXIgb2YgZ2VuZXMiKSkgKwogICAgQ09SUl9USEVNRQogIAogIHByaW50KGNvd3Bsb3Q6OnBsb3RfZ3JpZChwMSwgcDIsIG5jb2wgPSAyKSkKICAKICBnZ3NhdmUoIkthdGhpL3Bsb3RzL3RhZF9ib3VuZGFyaWVzX251bWJlcl9wZWFrc19nZW5lcy5wZGYiKQogIAogICMgY29tYmluZSB0aGUgYW5ub3RhdGlvbiBkYXRhZnJhbWUgd2l0aCB0aGUgcDJnIGxpbmtzIGRhdGFmcmFtZQogIHAyZ19qb2luIDwtIGxlZnRfam9pbihsaW5rcywgYXMuZGF0YS5mcmFtZShwb3NfYXRhY19ncmFuZ2VzKSwKICAgICAgICAgICAgICAgICAgICAgICAgYnkgPSAiaWR4QVRBQyIpCiAgcDJnX2pvaW4gPC0gbGVmdF9qb2luKHAyZ19qb2luLCBhcy5kYXRhLmZyYW1lKGdlbmVfYW5ubyksCiAgICAgICAgICAgICAgICAgICAgICAgIGJ5ID0gImlkeFJOQSIsIHN1ZmZpeCA9IGMoIi5hdGFjIiwgIi5ybmEiKSkKCiAgIyBjb21wdXRlIGRpc3RhbmNlIAogIHAyZ19qb2luIDwtIHAyZ19qb2luICU+JSAKICAgIG11dGF0ZShkaXN0YW5jZSA9IGFicyhzdGFydF9jb29yZCAtIG1pZGRsZSksIAogICAgICAgICAgIHJlbF9kaXN0YW5jZSA9IHN0YXJ0X2Nvb3JkIC0gbWlkZGxlKQogIAogICMgZmlsdGVyIGZvciB0aGUgcDJnIGxpbmtzIHdpdGhpbiB0YWQgYm91bmRhcmllcwogIGNvcnJfdGFkX2JvdW5kYXJ5IDwtIHAyZ19qb2luICU+JSAKICAgIHVuaXRlKHBlYWtfZ2VuZV90YWQsIGdlbmUsIGlkeEFUQUMsIHNlcCA9ICIjIiwgcmVtb3ZlID0gRkFMU0UpICU+JSAKICAgIGRwbHlyOjpmaWx0ZXIocGVha19nZW5lX3RhZCAlaW4lIGdlbmVfcGVha190YWRfZGYkcGVha19nZW5lX3RhZCkKCiAgIyMjIFBMT1RTCiAgCiAgcDEgPC0gY29ycl90YWRfYm91bmRhcnkgJT4lIAogICAgZ2dwbG90KCkgKwogICAgZ2VvbV9oaXN0b2dyYW0oYWVzKHggPSBDb3JyZWxhdGlvbiksIGJpbnMgPSAyMDAsIGZpbGwgPSAiIzY5YjNhMiIpICsKICAgIGxhYnModGl0bGUgPSAiUDJnIGxpbmtzIHdpdGhpbiBUQUQgYm91bmRhcmllcyIpICsKICAgIFRIRU1FX0xPTkcKICAKICBwMiA8LSBjb3JyX3RhZF9ib3VuZGFyeSAlPiUgCiAgICBnZ3Bsb3QoKSArCiAgICBnZW9tX2hpc3RvZ3JhbShhZXMoeCA9IGRpc3RhbmNlKSwgYmlucyA9IDIwMCwgZmlsbCA9ICIjNjliM2EyIikgKwogICAgbGFicyh4ID0gIkRpc3RhbmNlIChicCkiKSArCiAgICBUSEVNRV9MT05HCiAgCiAgcDMgPC0gY29ycl90YWRfYm91bmRhcnkgJT4lIAogICAgbXV0YXRlKGJpbiA9IGN1dF93aWR0aChkaXN0YW5jZSwgd2lkdGg9MTAwMDAwLCBib3VuZGFyeT0wKSkgJT4lIAogICAgZ2dwbG90KCkgKwogICAgZ2VvbV92aW9saW4oYWVzKHggPSBiaW4sIHkgPSBDb3JyZWxhdGlvbiksIGZpbGwgPSAiIzY5YjNhMiIsIGFscGhhID0gLjYsIHNjYWxlID0gIndpZHRoIikgKwogICAgZ2VvbV9ib3hwbG90KGFlcyh4ID0gYmluLCB5ID0gQ29ycmVsYXRpb24pLCBhbHBoYSA9IDApICsKICAgIGxhYnModGl0bGUgPSAiRGlzdGFuY2UgdnMuIENvcnJlbGF0aW9uLCB3aXRoaW4gVEFEIGJvdW5kYXJpZXMiLAogICAgICAgICB4ID0gIkRpc3RhbmNlICgxMDBrYiBiaW5zKSIpICsKICAgIHNjYWxlX3hfZGlzY3JldGUoZ3VpZGUgPSBndWlkZV9heGlzKGFuZ2xlID0gNDUpKSArCiAgICBUSEVNRV9MT05HCgogIHByaW50KGNvd3Bsb3Q6OnBsb3RfZ3JpZChwMSwgcDIsIG5jb2wgPSAxKSkKICAKICBnZ3NhdmUoIkthdGhpL3Bsb3RzL0Rpc3RhbmNlX2NvcnJfdGFkLnBkZiIpCiAgCiAgcHJpbnQocDMpCiAgZ2dzYXZlKCJLYXRoaS9wbG90cy9EaXN0YW5jZV92c19jb3JyLnBkZiIpCgogIAogICMjIyMgUExPVAogIHAxIDwtIGNvcnJfdGFkX2JvdW5kYXJ5ICU+JSBnZ3Bsb3QoKSArCiAgICBnZW9tX2hpc3RvZ3JhbShhZXMoeCA9IHJlbF9kaXN0YW5jZSksIGJpbnMgPSA1MDAsIGZpbGwgPSAiIzY5YjNhMiIpICsgCiAgICBzY2FsZV95X2xvZzEwKCkgKwogICAgbGFicyh0aXRsZSA9ICJQMmcgbGlua3Mgd2l0aGluIHRhZCBib3VuZGFyaWVzIiwKICAgICAgICAgeCA9ICJSZWxhdGl2ZSBkaXN0YW5jZSB0byBUU1MgKGJwKSIsIHkgPSAibG9nMTAoY291bnQpIikgKyAKICAgIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGMoMTAwMDAwLCAtMTAwMDAwKSwgY29sb3IgPSAib3JhbmdlIikgKwogICAgQ09SUl9USEVNRQogIAogIHByaW50KHAxKQogIGdnc2F2ZSgiS2F0aGkvcGxvdHMvUmVsYXRpdmVfZGlzdGFuY2VfdGFkLnBkZiIpCgogIAogIAogIHAyZ19saW5rc190YWQgPC0gTWF0cml4OjpzcGFyc2VNYXRyaXgoCiAgICAgIGkgPSBjb3JyX3RhZF9ib3VuZGFyeSRpZHhSTkEsIAogICAgICBqID0gY29ycl90YWRfYm91bmRhcnkkaWR4QVRBQywgCiAgICAgIHggPSBjb3JyX3RhZF9ib3VuZGFyeSRDb3JyZWxhdGlvbiwgCiAgICAgIGRpbXMgPSBjKG5yb3coZ2VuZV9hbm5vX29yaWdpbmFsKSwgbnJvdyhwZWFrX21hdCkpLAogICAgICBkaW1uYW1lcyA9IGxpc3QoZ2VuZV9hbm5vX29yaWdpbmFsJG5hbWUscm93bmFtZXMocGVha19tYXQpKQogICAgKQogIAogIAogIHByaW50KHBhc3RlMCgiVGhlIG1heGltdW0gdmFsdWUgaXM6ICIsIG1heChwMmdfbGlua3NfdGFkKSwgIiwgdGhlIG1pbnVtIHZhbHVlIGlzOiAiLCBtaW4ocDJnX2xpbmtzX3RhZCkgKSkKICAKICAKICAKICBwMmdfbGlua3NfdGFkIDwtIHAyZ19saW5rc190YWRbcm93U3VtcyhwMmdfbGlua3NfdGFkKSAhPSAwLCBdCiAgcDJnX2xpbmtzX3RhZCA8LSBwMmdfbGlua3NfdGFkWywgY29sU3VtcyhwMmdfbGlua3NfdGFkKSAhPSAwXQogIAogIHByaW50KHBhc3RlMCgiQWZ0ZXIgcmVtb3ZpbmcgYW55IHJvd3MgYW5kIGNvbHVtc24gd2hpY2ggZG8gbm90IGNvbnRhaW4gYW55IGxpbmtzIHdlIGFyZSBsZWZ0IHdpdGggIiwgbnJvdyhwMmdfbGlua3NfdGFkKSwgIiBnZW5lcyBhbmQgIiwgbmNvbChwMmdfbGlua3NfdGFkKSwgIiBwZWFrcy4iKSkKICAKICAKICAjIENvbXB1dGUgZ2VuZSBhY3Rpdml0eSBzY29yZXMKICB0YWRfc2NvcmVzIDwtIGdlbmVfYWN0aXZpdHlfc2NvcmVzKHBlYWtfbWF0X3N1Yltjb2xuYW1lcyhwMmdfbGlua3NfdGFkKSwgXSwgcDJnX2xpbmtzX3RhZCkKICAKICByZXR1cm4odGFkX3Njb3JlcykgCn0KZ2MocmVzZXQgPSBUUlVFKQpgYGAKCmBgYHtyLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9Nn0KdGFkX3Njb3JlcyA8LSB0YWRfYm91bmRhcmllc19wMmdfc2NvcmVzKHAyZ19tYXRfc3ViID0gcDJnX21hdF9zdWIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwZWFrX21hdCA9IFBFQUtfTUFULAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGlua3MgPSBsaW5rcywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwMmdfb3JpZ2luYWwgPSBwMmcsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VuZV9hbm5vID0gR0VORV9BTk5PLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGFkX2JvdW5kYXJpZXMgPSB0YWRfYm91bmRhcmllcykKCmdjKHJlc2V0ID0gVFJVRSkKYGBgCgoKYGBge3IsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD02fQpnZW5lX3dpbmRvd19hZ2cgPC0gY3JlYXRlX3NlYWNlbGxfYWdncmVnYXRlcyh0YWRfc2NvcmVzLCBzZWFjZWxscykKZ2VuZV93aW5kb3dfY29yciA8LSByb3d3aXNlX2NvcnJlbGF0aW9ucyhzZWFjZWxsX3JuYV9hZ2csIGdlbmVfd2luZG93X2FnZywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lID0gIkdlbmUgd2luZG93IGFyb3VuZCBUU1MiKQoKZ2VuZV93aW5kb3dfY29ycltbMl1dCgoKZ2dwbG90KCkgKwogIGdlb21fcG9pbnQoYWVzKHkgPSBzZWFjZWxsX2NvcnJfYXJjaHJbWzFdXVtuYW1lcyhnZW5lX3dpbmRvd19jb3JyW1sxXV0pXSwgCiAgICAgICAgICAgICAgICAgeCA9Z2VuZV93aW5kb3dfY29ycltbMV1dKSkgICsKICBnZW9tX2RlbnNpdHlfMmRfZmlsbGVkKGFlcyh5ID0gc2VhY2VsbF9jb3JyX2FyY2hyW1sxXV1bbmFtZXMoZ2VuZV93aW5kb3dfY29ycltbMV1dKV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeCA9IGdlbmVfd2luZG93X2NvcnJbWzFdXSksIGFscGhhID0gMC41KSArCiAgZ2VvbV9saW5lKGFlcyh4ID0gc2VhY2VsbF9jb3JyX2FyY2hyW1sxXV1bbmFtZXMoZ2VuZV93aW5kb3dfY29ycltbMV1dKV0sIAogICAgICAgICAgICAgICAgeSA9IHNlYWNlbGxfY29ycl9hcmNocltbMV1dW25hbWVzKGdlbmVfd2luZG93X2NvcnJbWzFdXSldLCAKICAgICAgICAgICAgICAgIGNvbG9yID0gInJlZCIpKSArCiAgbGFicyh4ID0gIkNvcnJlbGF0aW9uIGdlbmUgZXhwci4gJiBwMmcgYWN0aXZpdHkgc2NvcmVzIiwKICAgICAgICB5ID0gIkNvcnJlbGF0aW9uIGdlbmUgZXhwci4gJiBBcmNoUiBnZW5lIGFjdGl2aXR5IHNjb3JlcyIsIAogICAgICAgdGl0bGUgPSAiUDJnIGxpbmtzIHdpdGhpbiBUQUQgYm91bmRhcmllcyIpICsKICBDT1JSX1RIRU1FCgpgYGAKYGBge3IsIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTV9CmdncGxvdCgpICsKICBnZW9tX3BvaW50KGFlcyh5ID0gc2VhY2VsbF9jb3JyX3AyZ1tbMV1dW25hbWVzKGdlbmVfd2luZG93X2NvcnJbWzFdXSldLCAKICAgICAgICAgICAgICAgICB4ID1nZW5lX3dpbmRvd19jb3JyW1sxXV0pKSAgKwogIGdlb21fZGVuc2l0eV8yZF9maWxsZWQoYWVzKHkgPSBzZWFjZWxsX2NvcnJfcDJnW1sxXV1bbmFtZXMoZ2VuZV93aW5kb3dfY29ycltbMV1dKV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeCA9IGdlbmVfd2luZG93X2NvcnJbWzFdXSksIGFscGhhID0gMC41KSArCiAgZ2VvbV9saW5lKGFlcyh4ID0gc2VhY2VsbF9jb3JyX3AyZ1tbMV1dW25hbWVzKGdlbmVfd2luZG93X2NvcnJbWzFdXSldLCAKICAgICAgICAgICAgICAgIHkgPSBzZWFjZWxsX2NvcnJfcDJnW1sxXV1bbmFtZXMoZ2VuZV93aW5kb3dfY29ycltbMV1dKV0sIAogICAgICAgICAgICAgICAgY29sb3IgPSAicmVkIikpICsKICBsYWJzKHggPSAiQ29ycmVsYXRpb24gZ2VuZV9leHByLiAmIHAyZyBsaW5rcyB3aXRoaW4gVEFEIGJvdW5kYXJpZXMiLAogICAgICAgIHkgPSAiQ29ycmVsYXRpb24gZ2VuZSBleHByLiAmIGFsbCBwMmcgbGlua3MgIiwgCiAgICAgICB0aXRsZSA9ICJQMmcgbGlua3Mgd2l0aGluIFRBRCBib3VuZGFyaWVzIHZzLiBhbGwgbGlua3MiKSArCiAgQ09SUl9USEVNRQpgYGAKCgoKCgoKIyBBZGFwdGVkIEFyY2hyIEdlbmUgQWN0aXZpdHkgU2NvcmUgZnVuY3Rpb24KCkFyY2hSIHByb3ZpZGVzIGEgZnVuY3Rpb24gdG8gY29tcHV0ZSBnZW5lIGFjdGl2aXR5IHNjb3JlcyBiYXNlZCBvbiBhY2Nlc3NpYmlsaXR5IAppbiB0aGUgcmVnaW9ucyBhcm91bmQgdGhlIGdlbmUuIEZvciB0aGlzIGEgdGlsZSBtYXRyaXggaXMgdXNlZC4gVGhpcyB0aWxlIG1hdHJpeCAKaXMgYSBtYXRyaXggd2hlcmUgdGhlIGdlbm9tZSBpcyBkaXZpZGVkIGludG8gYmlucyBvZiA1MDBicC4gSWYgdGhlcmUgaXMgYQpUbjUgaW5zZXJ0aW9uIGluIGEgYmluIHRoZSBlbnRyeSB3aWxsIGJlIDEsIGlmIHRoZXJlIGlzIG5vIGluc2VydGlvbiB0aGUgZW50cnkKd2lsbCBiZSAwLiBJbXBvcnRhbnRseSwgdGhleSBjb21wYXJlZCB0aGVpciBmdW5jdGlvbiB0byA1MiBvdGhlciBmdW5jdGlvbnMKYW5kIGZvdW5kIHRoZWlyIG93biBmdW5jdGlvbiB0byBiZSB0aGUgYmVzdCBwZXJmb3JtaW5nLiAKCkhlcmUgSSB0cmllZCB0byBiZXR0ZXIgdW5kZXJzdGFuZCBob3cgdGhpcyBmdW5jdGlvbiB3b3JrcyBhbmQgY2hhbmdlZCB0aGUgc291cmNlIApjb2RlIG9mIHRoZSBBcmNoUiBmdW5jdGlvbiB0byBhbHNvIHRha2UgcGVhayBtYXRyaXggYXMgaW5wdXQgYW5kIGNvbXB1dGUgdGhlIGdlbmUgYWN0aXZpdHkgCmJhc2VkIG9uIHBlYWtzLCByYXRoZXIgdGhhbiBiYXNlZCBvbiB0aWxlcy4gQWRkaXRpb25hbGx5LCBJIGFkYXB0ZWQgdGhlIGZ1bmNpdG9uIAppbiBhIHdheSBzdWNoIHRoYXQgaXQgdGFrZXMgdGFkIGJvdW5kYXJpZXMgYXMgaW5wdXQgYW5kIHVzZXMgYWxsIHBlYWtzIHdoaWNoIGFyZSAKd2l0aGluIHRoZSBzYW1lIHRhZCBib3VuZGFyeSBhcyBhIGdlbmUgdG8gY29tcHV0ZSB0aGUgYWN0aXZpdHkgc2NvcmVzLiAKClRoZXJlIGFyZSB0d28gZGlmZmVyZW50IG9wdGlvbnMgZm9yIGNvbXB1dGluZyBnZW5lIGFjdGl2aXR5IHNjb3JlcyBpbiBBcmNoUi4gRmlyc3QsCndlIGNhbiB1c2UgdGhlIFRTUyBhbmQgY3JlYXRlIGEgZ2VuZSB3aW5kb3cgYXJvdW5kIGl0ICgrLy0gMTAwa3Agb2YgVFNTKS4gQWxsIAppbnNlcnRpb25zIGZvdW5kIHdpdGhpbiB0aWxlcyB3aXRoaW4gdGhpcyBnZW5lIHdpbmRvdyB3aWxsIGJlIGFjY3VtdWxhdGVkIGZvciB0aGUKZ2VuZSBhY3Rpdml0eSBzY29yZXMuIElmIHdlIHNldCB0aGUgb3B0aW9uICd1c2VHZW5lQm91bmRhcmllcz1UUlVFJyB0aGVuIHdlIHdpbGwgCm1ha2Ugc3VyZSB0aGF0IG5vIHJlZ2lvbnMgb3ZlcmxhcCBiZXR3ZWVuIGFueSB0d28gZ2VuZXMuIElmIHRoZSBnZW5lIHdpbmRvdyBvZiAKb25lIGdlbmUgb3ZlcmxhcHMgd2l0aCB0aGUgZ2VuZSB3aW5kb3cgb2YgYW5vdGhlciBnZW5lLCB0aG9zZSB0aWxlcyBhcmUgbm90IApjb25zaWRlcmVkIGFueW1vcmUuIFRoZSBkaXNhZHZhbnRhZ2Ugb2YgdGhpcyBhcHByb2FjIGlzIHRoYXQgZ2VuZXMgY2FuIGJlIHZlcnkgCmxhcmdlICg+MTAwYnApLCBtZWFuaW5nIHRoYXQgaW4gc29tZSBjYXNlcyB0aGUgMTAwa3AgZXh0ZW5zaW9uIGRvd25zdHJlYW0gb2YgdGhlClRTUyB3b3VsZCBub3QgZXZlbiBjb250YWluIHRoZSBlbnRpcmUgZ2VuZSBib2R5LiAKClNlY29uZCwgd2UgY2FuIHVzZSB0aGUgZW50aXJlIGdlbmUgYm9keSBhbmQgZXh0ZW5kIHRoZSBnZW5lIHdpbmRvdyBiZXlvbmQgdGhlIHN0YXJ0CmFuZCBlbmQgY29vcmRpbmF0ZXMgb2YgdGhlIGdlbmUgYm9keS4gSW1wb3J0YW50bHksIHRoZSBnZW5lIGJvZHkgaXMgZXh0ZW5kZWQgNWtiCnVwc3RyZWFtIG9mIHRoZSBUU1MsIHRvIGFsc28gaW5jbHVkZSB0aGUgcHJvbW90ZXIgcmVnaW9uLiBVc2luZyB0aGUgZW50aXJlIGdlbmUgCmJvZHkgaW5zdGVhZCBvZiBvbmx5IHRoZSBUU1MgY2FuIGJlIGFjaGlldmVkIGJ5IHNldHRpbmcgJ3VzZVRTUz1GQUxTRScuIEluIHRoaXMgCmFwcHJvYWNoIHRoZSBnZW5lIHdpbmRvdyBpcyBjcmVhdGVkIGJ5IGV4dGVuZGluZyAtMTAwa2IgdXBzdHJlYW0gb2YgdGhlIFRTUyAtNWtiCmFuZCArMTAwa2IgZG93bnN0cmVhbSBvZiB0aGUgZ2VuZSBlbmQgY29vcmRpbmF0ZS4gVGhpcyB3YXksIHRoZSBlbnRpcmUgZ2VuZSBib2R5IAp3aWxsIGJlIGluY2x1ZGVkIGluIHRoZSBnZW5lIHdpbmRvdy4gQW4gdW53YW50ZWQgY29uc2VxdWVuY2Ugb2YgdGhpcyBtaWdodCBiZQp0aGF0IHZlcnkgbGFyZ2UgZ2VuZXMgY291bGQgYmlhcyB0aGUgZ2VuZSBhY3Rpdml0eSBzY29yZXMuIFRoZXJlZm9yZSBBcmNoUiAKaW50cm9kdWNlcyBhIHdlaWdodCBmb3IgdGhlIGludmVyc2Ugb2YgdGhlIGdlbmUgYm9keSBzaXplIGFjY29yZGluZyB0bzoKCiR3ID0gXGZyYWN7MX17Z2VuZSBzaXplfSQgd2l0aCAkdyQgYmVpbmcgdGhlIGludmVyc2Ugb2YgdGhlIGdlbmUgc2l6ZS4KJAoKZ2VuZVJlZ2lvbnMkZ2VuZVdlaWdodCA9IDEgKyB3ICogKGdlbmVTY2FsZUZhY3RvciAtIDEpIC8gKG1heCh3KSAtIG1pbih3KSkkLiBUaGUgZGVmYXVsdApnZW5lU2NhbGVGYWN0b3IgaXMgNS4KCkFkZGl0aW9uYWxseSwgQXJjaFIgdXNlcyBhIGRpc3RhbmNlIHdlaWdodC4gRmFydGhlciBhd2F5IHRpbGVzL3BlYWtzIGFyZSBsZXNzIGxpa2VseSB0byAKaW50ZXJhY3Qgd2l0aCBhIFRTUyB0aGFuIGNsb3NlciB0aWxlcy9wZWFrcy4gSWYgdGhlIGZpcnN0IGFwcHJvYWNoLCB1c2luZyBvbmx5IHRoZQpUU1MsIHRoZSBkaXN0YW5jZSB3ZWlnaHRzIGFyZSBjb21wdXRlZCBhcyBmb2xsb3dzOgoKJHdlaWdodCA9IGVeey0oYWJzKGRpc3RUU1MvNTAwMCkpfSQgd2l0aCAkZGlzdFRTUyQgYmVpbmcgdGhlIGRpc3RhbmNlIGZyb20gdGhlClRTUy4gVGhpcyB3YXkgdGhlIHdlaWdodHMgZGVjYXkgZXhwb25lbnRpYWxseSB3aXRoIGRpc3RhbmNlLiBUaGUgY29uc3RhbnQgdmFsdWUKb2YgJDUwMDAkIGlzIGEgcGFyYW1ldGVyIHdoaWNoIGNvdWxkIGJlIG9wdGltaXplZCBmb3IgZGlmZmVyZW50IGdlbmVzIG9yIGRhdGFzZXRzLCAKYnV0IGhlcmUgd2Ugd2lsbCBrZWVwIGl0IGNvbnN0YW50LiAKCkluIGNhc2UgdGhlIGVudGlyZSBnZW5lIGJvZHkgaXMgdXNlZCwgdGhlIGRpc3RhbmNlIHdlaWdodHMgYXJlIGtlcHQgY29uc3RhbnQgCmZvciBhbGwgdGlsZXMvcGVha3Mgd2l0aGluIHRoZSBnZW5lIGJvZHkgYW5kIG9ubHkgZGVjYXkgYmV5b25kIHRoZSBnZW5lIGJvZHkuCgokd2VpZ2h0ID0gXGJlZ2lue2Nhc2VzfSBpZiAoLTVrYiBmcm9tIFRTUywgVFRTKTogMSArIGVeey0xfSBcXCBlbHNlOiBlXnstYWJzKGRpc3RHQi81MDAwKSArIGVeey0xfX0gXGVuZHtjYXNlc30kCgoKCgojIyBBcmNoUiBHZW5lIEFjdGl2aXR5IFNjb3JlcyB1c2luZyBUQUQgYm91bmRhcmllcwoKSW5zdGVhZCBvZiB1c2luZyBhICsvLTEwMGtiIHdpbmRvdyBhcm91bmQgdGhlIGdlbmUgYm9keSwgaW4gdGhlIGFkYXB0ZWQgCmZ1bmN0aW9uIGFsbCBwZWFrcyB3aGljaCBhcmUgd2l0aGluIHRoZSBzYW1lIFRBRCBib3VuZGFyeSBhcyB0aGUgZ2VuZSBvZiBpbnRlcmVzdAphcmUgY29uc2lkZXJlZCBmb3IgdGhlIGFjdGl2aXR5IHNjb3JlIG9mIHRoYXQgZ2VuZS4gVGhlIGRpc3RhbmNlIHdlaWdodCB3aXRoIApjID0gNTAwMCBpcyBrZXB0IHRoZSBzYW1lIGFzIGZvciB0aGUgZGVmYXVsdCBBcmNoUiBmdW5jdGlvbi4gQXMgY2FuIGJlIHNlZW4gYmVsb3csCmV4dGVuZGluZyB0aGUgZ2VuZSB3aW5kb3cgdG8gVEFEIGJvdW5kYXJpZXMgeWllbGRzIHZlcnkgc2ltaWxhciByZXN1bHRzIGNvbXBhcmVkCnRvIHRoZSBkZWZhdWx0IEFyY2hSIGZ1bmN0aW9uLiAKCmBgYCN7cn0KcHJvaiA8LSBsb2FkQXJjaFJQcm9qZWN0KCJLYXRoaS8wNl9nZW5lX2FjdGl2aXR5X3Njb3Jlcy8iKQoKcHJvaiA8LSBhZGRUQURHZW5lU2NvcmVNYXRyaXgoCiAgcHJvaiwKICBnZW5lcyA9IGdldEdlbmVzKHByb2opLAogIHBlYWtzID0gZ2V0UGVha1NldChwcm9qKSwKICB0YWRCb3VuZGFyaWVzID0gdGFkX2JvdW5kYXJpZXMsCiAgZ2VuZU1vZGVsID0gImV4cCgtYWJzKHgpLzUwMDAwMCkgKyBleHAoLTEpIiwKICBtYXRyaXhOYW1lID0gIkdlbmVTY29yZU1hdHJpeF90YWRzXzUwMGsiLAogIGV4dGVuZFVwc3RyZWFtID0gYygxMDAwLCAxMDAwMDApLAogIGV4dGVuZERvd25zdHJlYW0gPSBjKDEwMDAsIDEwMDAwMCksCiAgZ2VuZVVwc3RyZWFtID0gNTAwMCwgI05ldyBQYXJhbQogICNnZW5lRG93bnN0cmVhbSA9IDAsICNOZXcgUGFyYW0KICB1c2VHZW5lQm91bmRhcmllcyA9IEZBTFNFLAogIHVzZVRTUyA9IEZBTFNFLCAjTmV3IFBhcmFtCiAgZXh0ZW5kVFNTID0gRkFMU0UsCiAgdGlsZVNpemUgPSA1MDAsCiAgY2VpbGluZyA9IDQsCiAgZ2VuZVNjYWxlRmFjdG9yID0gNSwgI05ldyBQYXJhbQogIHNjYWxlVG8gPSAxMDAwMCwKICBleGNsdWRlQ2hyID0gYygiY2hyWSIsICJjaHJYIiwgImNock0iKSwKICBibGFja2xpc3QgPSBnZXRCbGFja2xpc3QocHJvaiksCiAgdGhyZWFkcyA9IDEsCiAgcGFyYWxsZWxQYXJhbSA9IE5VTEwsCiAgc3ViVGhyZWFkaW5nID0gVFJVRSwKICBmb3JjZSA9IFRSVUUsCiAgbG9nRmlsZSA9IGNyZWF0ZUxvZ0ZpbGUoIi5hZGRUQURHZW5lU2NvcmVNYXQiKSkKCnNjb3JlcyA8LSBnZXRNYXRyaXhGcm9tUHJvamVjdChwcm9qLCB1c2VNYXRyaXggPSAiR2VuZVNjb3JlTWF0cml4IikKc2NvcmVfbWF0IDwtIGFzc2F5cyhzY29yZXMpW1sxXV0Kcm93bmFtZXMoc2NvcmVfbWF0KSA8LSByb3dEYXRhKHNjb3JlcykkbmFtZQoKCiNzYXZlUkRTKHNjb3JlcywgInRhZF9zY29yZXMiKQpgYGAKCgpgYGAje3J9CmdncGxvdCgpICsKICBnZW9tX2hpc3RvZ3JhbShhZXMoeCA9IHJvd1N1bXMoc2NvcmVfbWF0KSksIGJpbnMgPSAyMDApCmBgYAoKCmBgYCN7cn0KIyBjb21wdXRlIGFnZ3JlZ2F0ZXMgb2YgQXJjaFIgZ2VuZSBhY3Rpdml0eSBzY29yZSBtYXRyaXgKZGVmYXVsdF9hcmNociA8LSBjcmVhdGVfc2VhY2VsbF9hZ2dyZWdhdGVzKGFyY2hyX3Njb3Jlc19tYXQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWFjZWxscykKIyBjb21wdXRlIGFnZ3JlZ2F0ZXMgZm9yIHRhZCBib3VuZGFyeSBBcmNoUiBnZW5lIGFjdGl2aXR5IHNjb3JlIG1hdHJpeAp0YWRfYXJjaHIgPC0gY3JlYXRlX3NlYWNlbGxfYWdncmVnYXRlcyhzY29yZV9tYXQsIHNlYWNlbGxzKQojIGNvbXB1dGUgYWdncmVnYXRlcyBvZiBnZW5lIGV4cHJlc3Npb24gbWF0cml4CnJuYV9odmcgPC0gY3JlYXRlX3NlYWNlbGxfYWdncmVnYXRlcyhleHByX3N1Yiwgc2VhY2VsbHMpCgojIGNvcnJlbGF0aW9uIGJldHdlZW4gZ2VuZSBleHByZXNzaW9uIHZhbHVlcyBhbmQgZGVmYXVsdCBBcmNociBnZW5lIGFjdGl2aXR5IHNjb3JlcwpkZWZhdWx0X2FyY2hyX2NvcnIgPC0gcm93d2lzZV9jb3JyZWxhdGlvbnMocm5hX2h2ZywgZGVmYXVsdF9hcmNociwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQXJjaFIgZ2VuZSBhY3Rpdml0eSBzY29yZXMsIFNFQWNlbGxzIikKIyBjb3JyZWxhdGlvbiBiZXR3ZWVuIGdlbmUgZXhwcmVzc2lvbiBhbmQgVEFEIGJvdW5kYXJ5IGdlbmUgYWN0aXZpdHkgc2NvcmVzCnRhZF9jb3JyIDwtIHJvd3dpc2VfY29ycmVsYXRpb25zKHJuYV9odmcsIHRhZF9hcmNociwgIkFyY2hSIGdlbmUgYWN0aXZpdHkgc2NvcmVzIHdpdGhpbiBUQUQgYm91bmRhcmllcywgU0VBQ2VsbHMiKQoKY293cGxvdDo6cGxvdF9ncmlkKGRlZmF1bHRfYXJjaHJfY29ycltbMl1dLCB0YWRfY29ycltbMl1dLCBuY29sID0gMikKCmdncGxvdCgpICsKICBnZW9tX3BvaW50KGFlcyh4ID0gdGFkX2NvcnJbWzFdXSwgeSA9IGRlZmF1bHRfYXJjaHJfY29ycltbMV1dW25hbWVzKHRhZF9jb3JyW1sxXV0pXSkpICsKICBnZW9tX2RlbnNpdHlfMmRfZmlsbGVkKGFlcyh4ID0gdGFkX2NvcnJbWzFdXSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGRlZmF1bHRfYXJjaHJfY29ycltbMV1dW25hbWVzKHRhZF9jb3JyW1sxXV0pXSksCiAgICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IC41KSArCiAgZ2VvbV9saW5lKGFlcyh4ID0gZGVmYXVsdF9hcmNocl9jb3JyW1sxXV0sIHkgPSBkZWZhdWx0X2FyY2hyX2NvcnJbWzFdXSksIGNvbCA9ICJyZWQiKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIk5vbmUiKSAgKwogIGxhYnMoeCA9ICJDb3JyZWxhdGlvbiBnZW5lIGV4cHJlc3Npb24gJiBBcmNoUiBUQUQgYm91bmRhcnkgc2NvcmVzIiwKICAgICAgICB0aXRsZSA9ICJSZXN0cmljdGluZyBBcmNoUiBzY29yZXMgdG8gd2l0aGluIFRBRCBib3VuZGFyaWVzIiwKICAgICAgICB5ID0gIkNvcnJlbGF0aW9uIGdlbmUgZXhwcmVzc2lvbiAmIEFyY2hSIGdlbmUgYWN0aXZpdHkgc2NvcmVzIikKCmBgYAoKCiMjIyBUQUQgYm91bmRhcmVzIEU3LjUKClNpbmNlIHRoZSBUQUQgYm91bmRhcmllcyB1c2VkIGhlcmUsIGFyZSBmcm9tIGdhc3RydWxhdGlvbiBkYXkgRTcuNS4gRm9yIHRoZSBsYXRlcgp0aW1lIHBvaW50cyBubyBUQUQgYm91bmRhcmllcyBhcmUgYXZhaWxhYmxlLiBUaGVyZWZvcmUsIGluIHRoZSBmb2xsb3dpbmcgSSB3aWxsIGNoZWNrIAppZiB0aGUgcmVzdWx0cyBpbXByb3ZlIGluIGNvbXBhcmlzb24gdG8gdGhlIGRlZmF1bHQgQXJjaFIgZnVuY3Rpb24gd2hlbiB1c2luZyBvbmx5IApkYXRhIGZyb20gRTcuNS4gU2luY2UgZHVyaW5nIGdhc3RydWxhdGlvbiBUQUQgYm91bmRhcmllcyBtaWdodCBzdGlsbCBiZSB2ZXJ5IApkeW5hbWljIHRoZSBpbXByb3ZpbmcgZWZmZWN0IG9mIFRBRCBib3VuZGFyaWVzIGNvdWxkIGJlIGRpbHV0ZWQgYnkgbGF0ZXIgdGltZSBwb2ludHMKaW4gdGhlIGRhdGEuIAoKV2hhdCBhcmUgdGggZ2VuZXMgd2hpY2ggZ2V0IHplcm8gYWN0aXZpdHkgc2NvcmVzPyBEbyB0aGV5IGxpZSBvdXRzaWRlIHRoZSBUQUQKYm91bmRhcmllcz8KCmBgYCN7cn0KZTc1X21ldGEgPC0gY29sRGF0YShzY29yZXMpICU+JSBhcy5kYXRhLmZyYW1lKCkgJT4lCiAgZmlsdGVyKFNhbXBsZSAlaW4lIGMoIkU3LjVfcmVwMSIsICJFNy41X3JlcDIiKSkgJT4lIAogIHJvd25hbWVzX3RvX2NvbHVtbigiY2VsbCIpCm1hdF83NSA8LSBzY29yZV9tYXRbcm93bmFtZXMoc2NvcmVfbWF0KSAlaW4lIHJvd25hbWVzKGV4cHJfc3ViKSwgZTc1X21ldGEkY2VsbF0Kc2VhY2VsbHNfc3ViIDwtIHNlYWNlbGxzICU+JSBmaWx0ZXIoaW5kZXggJWluJSBjb2xuYW1lcyhtYXRfNzUpKSAKCiMgY29tcHV0ZSBhZ2dyZWdhdGVzIG9mIEFyY2hSIGdlbmUgYWN0aXZpdHkgc2NvcmUgbWF0cml4CmRlZmF1bHRfYXJjaHIgPC0gY3JlYXRlX3NlYWNlbGxfYWdncmVnYXRlcyhhcmNocl9zY29yZXNfbWF0W3Jvd25hbWVzKGFyY2hyX3Njb3Jlc19tYXQpICVpbiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByb3duYW1lcyhleHByX3N1YiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlNzVfbWV0YSRjZWxsXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlYWNlbGxzX3N1YikKIyBjb21wdXRlIGFnZ3JlZ2F0ZXMgZm9yIHRhZCBib3VuZGFyeSBBcmNoUiBnZW5lIGFjdGl2aXR5IHNjb3JlIG1hdHJpeAp0YWRfYXJjaHIgPC0gY3JlYXRlX3NlYWNlbGxfYWdncmVnYXRlcyhtYXRfNzUsIHNlYWNlbGxzX3N1YikKIyBjb21wdXRlIGFnZ3JlZ2F0ZXMgb2YgZ2VuZSBleHByZXNzaW9uIG1hdHJpeApybmFfaHZnIDwtIGNyZWF0ZV9zZWFjZWxsX2FnZ3JlZ2F0ZXMoZXhwcl9zdWJbLCBlNzVfbWV0YSRjZWxsXSwgc2VhY2VsbHNfc3ViKQoKIyBjb3JyZWxhdGlvbiBiZXR3ZWVuIGdlbmUgZXhwcmVzc2lvbiB2YWx1ZXMgYW5kIGRlZmF1bHQgQXJjaHIgZ2VuZSBhY3Rpdml0eSBzY29yZXMKZGVmYXVsdF9hcmNocl9jb3JyIDwtIHJvd3dpc2VfY29ycmVsYXRpb25zKHJuYV9odmcsIGRlZmF1bHRfYXJjaHIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkFyY2hSIGdlbmUgYWN0aXZpdHkgc2NvcmVzLCBTRUFjZWxscyIpCiMgY29ycmVsYXRpb24gYmV0d2VlbiBnZW5lIGV4cHJlc3Npb24gYW5kIFRBRCBib3VuZGFyeSBnZW5lIGFjdGl2aXR5IHNjb3Jlcwp0YWRfY29yciA8LSByb3d3aXNlX2NvcnJlbGF0aW9ucyhybmFfaHZnLCB0YWRfYXJjaHIsICJBcmNoUiBnZW5lIGFjdGl2aXR5IHNjb3JlcyB3aXRoaW4gVEFEIGJvdW5kYXJpZXMsIFNFQUNlbGxzIikKCmNvd3Bsb3Q6OnBsb3RfZ3JpZChkZWZhdWx0X2FyY2hyX2NvcnJbWzJdXSwgdGFkX2NvcnJbWzJdXSwgbmNvbCA9IDIpCgpnZ3Bsb3QoKSArCiAgZ2VvbV9wb2ludChhZXMoeCA9IHRhZF9jb3JyW1sxXV0sIHkgPSBkZWZhdWx0X2FyY2hyX2NvcnJbWzFdXVtuYW1lcyh0YWRfY29ycltbMV1dKV0pKSArCiAgZ2VvbV9kZW5zaXR5XzJkX2ZpbGxlZChhZXMoeCA9IHRhZF9jb3JyW1sxXV0sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBkZWZhdWx0X2FyY2hyX2NvcnJbWzFdXVtuYW1lcyh0YWRfY29ycltbMV1dKV0pLAogICAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAuNSkgKwogIGdlb21fbGluZShhZXMoeCA9IGRlZmF1bHRfYXJjaHJfY29ycltbMV1dLCB5ID0gZGVmYXVsdF9hcmNocl9jb3JyW1sxXV0pLCBjb2wgPSAicmVkIikgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJOb25lIikgICsKICBsYWJzKHggPSAiQ29ycmVsYXRpb24gZ2VuZSBleHByZXNzaW9uICYgQXJjaFIgVEFEIGJvdW5kYXJ5IHNjb3JlcyIsCiAgICAgICAgdGl0bGUgPSAiUmVzdHJpY3RpbmcgQXJjaFIgc2NvcmVzIHRvIHdpdGhpbiBUQUQgYm91bmRhcmllcyIsCiAgICAgICAgeSA9ICJDb3JyZWxhdGlvbiBnZW5lIGV4cHJlc3Npb24gJiBBcmNoUiBnZW5lIGFjdGl2aXR5IHNjb3JlcyIpCmBgYAoKV2hhdCBhcmUgdGhlIGdlbmVzIHdoaWNoIGdldCB6ZXJvIGNvcnJlbGF0aW9uIHdpdGggZ2VuZSBleHByZXNzaW9uPwoKVGhlcmUgYXJlIDggZ2VuZXMgd2hpY2ggZ2V0IHplcm8gY29ycmVsYXRpb24gdmFsdWVzIGJldHdlZW4gZ2VuZSBhY3Rpdml0eSBzY29yZXMKYW5kIGdlbmUgZXhwcmVzc2lvbi4gVGhpcyBpcywgYmVjYXVzZSB0aGV5IGdldCB6ZXJvIGFjdGl2aXR5IHNjb3JlcyBpbiBhbGwgY2VsbHMuIEhvd2V2ZXIsCnRoZSBzYW1lIGdlbmVzIGFyZSBleHByZXNzZWQgdG8gY2VydGFpbiBsZXZlbHMgYWNjb3JkaW5nIHRvIHRoZSBnZW5lIGV4cHJlc3Npb24gCm1hdHJpeC4gVHdvIG9mIHRoZSBnZW5lcyBhbHNvIGdldCB6ZXJvIGFjdGl2aXR5IHNjb3JlcyBpbiB0aGUgZGVmYXVsdCBBcmNoUiAKZnVuY3Rpb24gKFBybDJjMywgR3NkbWM0KS4gVGhlIHJlYXNvbiBmb3IgaXMgbm90IGltbWVkaWF0ZWx5IGNsZWFyLCBzaW5jZSBhcyBsb25nCmFzIHRoZXJlIGFyZSBwZWFrcyBpbiBhIGdlbmUgd2luZG93LCB0aGUgZGlzdGFuY2Ugd2VpZ2h0IHdpbGwgYXQgbGVhc3QgYmUgMC4zNiAKYWNjb3JpbmRnIHRvIHRoZSBmb3JtdWxhLiBPbmUgcmVhc29uIGZvciB6ZXJvIHZhbHVlcyBjb3VsZCBiZSB0aGF0IHRoZXNlIGdlbmVzIGxpZSBvdXRzaWRlIFRBRCAKYm91bmRhcmllcyB3aWNoIGlzIGluIGZhY3QgdGhlIGNhc2UgZm9yIGZvdXIgb3V0IG9mIDggZ2VuZXMuCgoKV2hhdCBpcyB0aGUgZXhwbGFuYXRpb24gd2h5IEx5ejIgYW5kIEdtMTM1NDcgIGdldCBhY3Rpdml0eSBzY29yZXMgb2YgemVybz8KCmBgYCN7cn0KemVyb19nZW5lcyA8LSBuYW1lcyh0YWRfY29ycltbMV1dW3RhZF9jb3JyW1sxXV0gPT0gMF0pCgp6ZXJvX21hdCA8LSBzY29yZV9tYXRbemVyb19nZW5lcywgXQpyb3dTdW1zKHplcm9fbWF0KSAKCgojIGNoZWNrIHRoZSBkZWZhdWx0IEFyY2hSIHNjb3JlcyBmb3IgdGhlc2UgZ2VuZXMKcm93U3VtcyhhcmNocl9zY29yZXNfbWF0W3plcm9fZ2VuZXMsIF0pCgojIGNoZWNrIHRoZSBnZW5lIGV4cHJlc3Npb24gY291dG5zIGZvciB0aGVzZSBnZW5lcwpyb3dTdW1zKGV4cHJfbWF0W3plcm9fZ2VuZXMsXSkKCgpwMmdfcG9zIDwtIHAyZyAlPiUgYXMuZGF0YS5mcmFtZSgpICU+JSBmaWx0ZXIoQ29ycmVsYXRpb24gPiAwKSAlPiUKICB1bml0ZShsaW5rLCBpZHhSTkEsIGlkeEFUQUMsIHNlcCA9ICIlIiwgcmVtb3ZlID0gRkFMU0UpCgpnZW5lX2Fubm9fYWxsIDwtIHJvd0RhdGEoZ2VuZV9leHByKSAlPiUgYXMuZGF0YS5mcmFtZSgpICU+JQogIG11dGF0ZShpZHhSTkEgPSBzZXEobnJvdyguKSkpICU+JSAKICBmaWx0ZXIoaWR4Uk5BICVpbiUgcDJnX3BvcyRpZHhSTkEpICU+JQogIG11dGF0ZShzdHJhbmQgPSBpZmVsc2Uoc3RyYW5kID09IDEsICIrIiwgIi0iKSkgJT4lCiAgbXV0YXRlKHN0YXJ0X2Nvb3JkID0gaWZlbHNlKHN0cmFuZCA9PSAiKyIsIHN0YXJ0LCBlbmQpKSAlPiUgCiAgcmVuYW1lKGdlbmUgPSBuYW1lKSAjJT4lIEdSYW5nZXMoKQoKIyBzdWJzZXQgYXRhYyBncmFuZ2VzICYgZ2V0IG1pZGRsZSBvZiBlYWNoIHBlYWsKcG9zX2F0YWNfZ3Jhbmdlc19hbGwgPC0gbWV0YWRhdGEocDJnKVtbMV1dICAlPiUgCiAgYXMuZGF0YS5mcmFtZSgpICU+JQogIG11dGF0ZShpZHhBVEFDID0gc2VxKG5yb3coLikpKSAlPiUgCiAgIyBncm91cF9ieShzZXFuYW1lcykgJT4lCiAgIyBtdXRhdGUoaWR4ID0gc2VxX2Fsb25nKHNlcW5hbWVzKSkgJT4lIAogICMgdW5ncm91cCAlPiUKICAjdGlkeXI6OnVuaXRlKGNocl9pZHgsIHNlcW5hbWVzLCBpZHgsIHJlbW92ZSA9IEZBTFNFLCBzZXAgPSAiXyIpICU+JSAKICBmaWx0ZXIoaWR4QVRBQyAlaW4lIHAyZ19wb3MkaWR4QVRBQykgJT4lIAogIG11dGF0ZShtaWRkbGUgPSBzdGFydCArIDMwMCkgIyU+JSBHUmFuZ2VzKCkgCgoKCiMgY29tYmluZSB0aGUgdGhyZWUgZGF0YWZyYW1lcwpwMmdfam9pbl9hbGwgPC0gbGVmdF9qb2luKHAyZ19wb3MsIGFzLmRhdGEuZnJhbWUocG9zX2F0YWNfZ3Jhbmdlc19hbGwpLAogICAgICAgICAgICAgICAgICAgICAgYnkgPSAiaWR4QVRBQyIpCnAyZ19qb2luX2FsbCA8LSBsZWZ0X2pvaW4ocDJnX2pvaW5fYWxsLCBhcy5kYXRhLmZyYW1lKGdlbmVfYW5ub19hbGwpLAogICAgICAgICAgICAgICAgICAgICAgYnkgPSAiaWR4Uk5BIiwgc3VmZml4ID0gYygiLmF0YWMiLCAiLnJuYSIpKQoKCnAyZ19qb2luX2FsbCA8LSBwMmdfam9pbl9hbGwgJT4lIAogIG11dGF0ZShkaXN0YW5jZSA9IGFicyhzdGFydF9jb29yZCAtIG1pZGRsZSkpCgoKCiAgIyBmaW5kIG92ZXJsYXBwaW5nIHBlYWtzIGFuZCBnZW5lIHdpbmRvdyBpbiBjaHJvbW9zb21lLWF3YXJlIGZhc2hpb24KdGFkX292ZXJsYXBzX2dlbmVzIDwtIChmaW5kT3ZlcmxhcHMoZ2VuZV9hbm5vX2FsbCAlPiUgR1JhbmdlcygpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRhZF9ib3VuZGFyaWVzKSkKCgojIGdldCBhbGwgZ2VuZXMgd2hpY2ggYXJlIGZvdW5kIHdpdGhpbiB0YWQgYm91ZG5hcmllcwpnZW5lX2Fubm9fd2l0aGluX3RhZCA8LSBnZW5lX2Fubm9fYWxsW3F1ZXJ5SGl0cyh0YWRfb3ZlcmxhcHNfZ2VuZXMpLF0KCgojIExldHMgZXhhbWluZSB0aGUgZ2VuZXMgd2hpY2ggYXJlIGZvdW5kIHdpdGhpbiB0YWQgYm91bmRhcmllcywgYnV0CiMgZ2V0IGFuIGFjdGl2aXR5IHNjb3JlIG9mIHplcm8gbmV2ZXJ0aGVsZXNzCmdlbmVfYW5ub193aXRoaW5fdGFkICU+JSBmaWx0ZXIoZ2VuZSAlaW4lIHplcm9fZ2VuZXMpCgoKZ2VuZV9uYW1lID0gIkx5ejIiCmNocl9uYW1lID0gImNocjIiCmNocnggPC0gdGFkX2JvdW5kYXJpZXMgJT4lIGFzLmRhdGEuZnJhbWUoKSAlPiUgZmlsdGVyKHNlcW5hbWVzID09IGNocl9uYW1lKSAlPiVHUmFuZ2VzKCkKaGl0cyA8LSBmaW5kT3ZlcmxhcHMoZ2VuZV9hbm5vX2FsbCAlPiUgZmlsdGVyKGdlbmUgPT0gZ2VuZV9uYW1lKSAlPiUgR1JhbmdlcygpLCAgY2hyeCkKc3RhcnRfdGFkIDwtIHN0YXJ0KGNocnhbc3ViamVjdEhpdHMoaGl0cyksXSkKZW5kX3RhZCA8LSBlbmQoY2hyeFtzdWJqZWN0SGl0cyhoaXRzKSxdKQpzdGFydF9nZW5lIDwtIHN0YXJ0KGdlbmVfYW5ub19hbGwgJT4lIGZpbHRlcihnZW5lID09IGdlbmVfbmFtZSkgJT4lIEdSYW5nZXMoKSkKZW5kX2dlbmUgPC0gZW5kKGdlbmVfYW5ub19hbGwgJT4lIGZpbHRlcihnZW5lID09IGdlbmVfbmFtZSkgJT4lIEdSYW5nZXMoKSkKcHJpbnQocGFzdGUwKCJPdXQgb2YgIiwgbGVuZ3RoKHplcm9fZ2VuZXMpLCAiIGdlbmVzLCAgIiwgIGxlbmd0aCh6ZXJvX2dlbmVzW3plcm9fZ2VuZXMgJWluJSBnZW5lX2Fubm9fd2l0aGluX3RhZCRnZW5lXSkgLCAiIGdlbmVzIGFyZSBmb3VuZCB3aXRoaW4gdGFkIGJvdW5kYXJpZXMsIHdoaWxlIHRoZSByZXN0IGFyZSBub3QuIikpCnBvc19hdGFjX2dyYW5nZXNfYWxsICU+JSBhcy5kYXRhLmZyYW1lKCkgJT4lIGZpbHRlcihzZXFuYW1lcyA9PSBjaHJfbmFtZSkgJT4lCiAgZmlsdGVyKHN0YXJ0ID4gc3RhcnRfdGFkICYgZW5kIDwgZW5kX3RhZCkKCiMgCiMgemVyb19nZW5lcwojIAojIGlkeCA8LSAoZ2VuZV9hbm5vX2FsbCAlPiUgZmlsdGVyKGdlbmUgJWluJSB6ZXJvX2dlbmVzKSkkaWR4Uk5BCiMgCiMgaWR4ICVpbiUgZ2VuZV9hbm5vX2FsbFt0YWRfb3ZlcmxhcHNfZ2VuZXMkcXVlcnlIaXRzLApgYGAKCgoKIyMgQXJjaFIgR2VuZSBBY3Rpdml0eSBTY29yZXMgdXNpbmcgZ2VuZSBib2R5Cgo8ZGV0YWlscz4KPHN1bW1hcnk+QXJjaFIgR2VuZSBBY3Rpdml0eSBTY29yZXMgdXNpbmcgZ2VuZSBib2R5PC9zdW1tYXJ5PgoKYGBgI3tyfQoKI3NhdmVBcmNoUlByb2plY3QoQXJjaFJQcm9qID0gcHJvaiwgb3V0cHV0RGlyZWN0b3J5ID0gIjEyX0NvcHk0LyIsIGxvYWQgPSBGQUxTRSkKbG9hZEFyY2hSUHJvamVjdCgiMTJfYWN0aXZpdHlfc2NvcmVzX2dlbmVfYm9keV9wZWFrcy8iKQoKcHJvaiA8LSBhZGRLYXRoaUdlbmVTY29yZU1hdHJpeCgKICBwcm9qLAogIGdlbmVzID0gZ2V0R2VuZXMocHJvaiksCiAgcGVha3MgPSBnZXRQZWFrU2V0KHByb2opLAogIGdlbmVNb2RlbCA9ICJleHAoLWFicyh4KS81MDAwKSArIGV4cCgtMSkiLAogIG1hdHJpeE5hbWUgPSAiR2VuZVNjb3JlTWF0cml4IiwKICBleHRlbmRVcHN0cmVhbSA9IGMoMTAwMCwgMTAwMDAwKSwKICBleHRlbmREb3duc3RyZWFtID0gYygxMDAwLCAxMDAwMDApLAogICNnZW5lVXBzdHJlYW0gPSA1MDAwLCAjTmV3IFBhcmFtCiAgI2dlbmVEb3duc3RyZWFtID0gMCwgI05ldyBQYXJhbQogIHVzZUdlbmVCb3VuZGFyaWVzID0gVFJVRSwKICB1c2VUU1MgPSBGQUxTRSwgI05ldyBQYXJhbQogIGV4dGVuZFRTUyA9IEZBTFNFLAogIHRpbGVTaXplID0gNTAwLAogIGNlaWxpbmcgPSA0LAogIGdlbmVTY2FsZUZhY3RvciA9IDUsICNOZXcgUGFyYW0KICBzY2FsZVRvID0gMTAwMDAsCiAgZXhjbHVkZUNociA9IGMoImNoclkiLCAiY2hyTSIpLAogIGJsYWNrbGlzdCA9IGdldEJsYWNrbGlzdChwcm9qKSwKICB0aHJlYWRzID0gMSwKICBwYXJhbGxlbFBhcmFtID0gTlVMTCwKICBzdWJUaHJlYWRpbmcgPSBUUlVFLAogIGZvcmNlID0gVFJVRSwKICBsb2dGaWxlID0gY3JlYXRlTG9nRmlsZSgiLmFkZEthdGhpR2VuZVNjb3JlTWF0IikpCgoKc2NvcmVzIDwtIGdldE1hdHJpeEZyb21Qcm9qZWN0KHByb2osIHVzZU1hdHJpeCA9ICJHZW5lU2NvcmVNYXRyaXgiKQoKc2NvcmVzX21hdCA8LSBhc3NheXMoc2NvcmVzKVtbMV1dCnJvd25hbWVzKHNjb3Jlc19tYXQpIDwtIHJvd0RhdGEoc2NvcmVzKSRuYW1lCgoKIyBzY2UgPC0gU2luZ2xlQ2VsbEV4cGVyaW1lbnQobGlzdChzY29yZXM9c2NvcmVzX21hdCksCiMgICAgICAgICAgICAgICAgICAgICAgICAgICByb3dEYXRhID0gYXMuZGF0YS5mcmFtZShyb3dEYXRhKHNjb3JlcykpLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sRGF0YSA9IGFzLmRhdGEuZnJhbWUoY29sbmFtZXMoc2NvcmVzX21hdCkpKQojIAojIHdyaXRlSDVBRChzY2UsICIvb21pY3MvZ3JvdXBzL09FMDUzMy9pbnRlcm5hbC9rYXRoYXJpbmEvc2NEb1JJL2dhc3RydWxhdGlvbl9kYXRhL2p1cHl0ZXJfbm90ZWJvb2tzL3AyZ19nZW5lX2FjdGl2aXR5X3Njb3Jlcy9hcmNocl9zY29yZXNfZ2VuZV9ib2R5X3BlYWtfYmFzZWQiLCBYX25hbWUgPSAic2NvcmVzIikKCmBgYAo8L2RldGFpbHM+CgpDb3JyZWxhdGluZyBnZW5lIGV4cHJlc3Npb24gd2l0aCBhY3Rpdml0eSBzY29yZXM6CgpgYGAje3J9CmFyY2hyX2dlbmVfYm9keV9hZ2cgPC0ga25uX2FnZ3JlZ2F0ZXMoc2NvcmVzX21hdCwgY2VsbF9hZ2dfbGlzdCkKCmdlbmVfYm9keV9rbm4gPC0gcm93d2lzZV9jb3JyZWxhdGlvbnMocm5hX2FnZywgYXJjaHJfZ2VuZV9ib2R5X2FnZywgIkFyY2hSIGdlbmUgYWN0aXZpdHkgc2NvcmVzIGJhc2VkIG9uIHBlYWsgbWF0cml4LCB1c2luZyBnZW5lIGJvZHkiKQoKCmNvd3Bsb3Q6OnBsb3RfZ3JpZChhcmNocl9rbm5bWzJdXSwgZ2VuZV9ib2R5X2tubltbMl1dLCBuY29sID0gMikKCnAxIDwtIGdncGxvdCgpICsgZ2VvbV9kZW5zaXR5XzJkX2ZpbGxlZChhZXMoeCA9IGdlbmVfYm9keV9rbm5bWzFdXSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGFyY2hyX2tubltbMV1dKSwgYWxwaGEgPSAuNSkgKwogIGdlb21fcG9pbnQoYWVzKHggPSBnZW5lX2JvZHlfa25uW1sxXV0sIHkgPSBhcmNocl9rbm5bWzFdXSkpICsKICBnZW9tX2xpbmUoYWVzKHggPSBnZW5lX2JvZHlfa25uW1sxXV0sIHkgPSBnZW5lX2JvZHlfa25uW1sxXV0pLCBjb2wgPSAicmVkIikgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJOb25lIikgCmBgYAoKCiMjIEFyY2hSIEdlbmUgQWN0aXZpdHkgU2NvcmVzIHVzaW5nIFRTUywgbm8gZ2VuZSBib2R5Cgo8ZGV0YWlscz4KPHN1bW1hcnk+QXJjaFIgR2VuZSBBY3Rpdml0eSBTY29yZXMgdXNpbmcgVFNTLCBubyBnZW5lIGJvZHk8L3N1bW1hcnk+CgoKYGBgI3tyfQoKcHJvaiA8LSBsb2FkQXJjaFJQcm9qZWN0KCIxMl9hY3Rpdml0eV9zY29yZXNfVFNTX3RpbGVzLyIpCgpwcm9qIDwtIGFkZEdlbmVTY29yZU1hdHJpeCgKICBwcm9qLAogIGdlbmVzID0gZ2V0R2VuZXMocHJvaiksCiAgZ2VuZU1vZGVsID0gImV4cCgtYWJzKHgpLzUwMDApIiwKICBtYXRyaXhOYW1lID0gIkdlbmVTY29yZU1hdHJpeCIsCiAgZXh0ZW5kVXBzdHJlYW0gPSBjKDEwMDAsIDEwMDAwMCksCiAgZXh0ZW5kRG93bnN0cmVhbSA9IGMoMTAwMCwgMTAwMDAwKSwKICAjZ2VuZVVwc3RyZWFtID0gNTAwMCwgI05ldyBQYXJhbQogICNnZW5lRG93bnN0cmVhbSA9IDAsICNOZXcgUGFyYW0KICB1c2VHZW5lQm91bmRhcmllcyA9IFRSVUUsCiAgdXNlVFNTID0gVFJVRSwgI05ldyBQYXJhbQogIGV4dGVuZFRTUyA9IEZBTFNFLAogIHRpbGVTaXplID0gNTAwLAogIGNlaWxpbmcgPSA0LAogIGdlbmVTY2FsZUZhY3RvciA9IDUsICNOZXcgUGFyYW0KICBzY2FsZVRvID0gMTAwMDAsCiAgZXhjbHVkZUNociA9IGMoImNoclkiLCAiY2hyTSIpLAogIGJsYWNrbGlzdCA9IGdldEJsYWNrbGlzdChwcm9qKSwKICB0aHJlYWRzID0gMSwKICBwYXJhbGxlbFBhcmFtID0gTlVMTCwKICBzdWJUaHJlYWRpbmcgPSBUUlVFLAogIGZvcmNlID0gVFJVRSwKICBsb2dGaWxlID0gY3JlYXRlTG9nRmlsZSgiLmFkZEdlbmVTY29yZU1hdHJpeCIpKQoKCnNjb3JlcyA8LSBnZXRNYXRyaXhGcm9tUHJvamVjdChwcm9qLCB1c2VNYXRyaXggPSAiR2VuZVNjb3JlTWF0cml4IikKCnNjb3Jlc19tYXQgPC0gYXNzYXlzKHNjb3JlcylbWzFdXQpyb3duYW1lcyhzY29yZXNfbWF0KSA8LSByb3dEYXRhKHNjb3JlcykkbmFtZQoKCiMgc2NlIDwtIFNpbmdsZUNlbGxFeHBlcmltZW50KGxpc3Qoc2NvcmVzPXNjb3Jlc19tYXQpLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgcm93RGF0YSA9IGFzLmRhdGEuZnJhbWUocm93RGF0YShzY29yZXMpKSwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbERhdGEgPSBhcy5kYXRhLmZyYW1lKGNvbG5hbWVzKHNjb3Jlc19tYXQpKSkKIyAKIyB3cml0ZUg1QUQoc2NlLCAiL29taWNzL2dyb3Vwcy9PRTA1MzMvaW50ZXJuYWwva2F0aGFyaW5hL3NjRG9SSS9nYXN0cnVsYXRpb25fZGF0YS9qdXB5dGVyX25vdGVib29rcy9wMmdfZ2VuZV9hY3Rpdml0eV9zY29yZXMvYXJjaHJfc2NvcmVzX3RzcyIsIFhfbmFtZSA9ICJzY29yZXMiKQoKYGBgCgojIyBBcmNoUiBnZW5lIGFjdGl2aXR5IHNjb3JlcyBjb21wdXRlZCB1c2luZyBUU1MsIG5vIGdlbmUgYm9keSBhbmQgUGVha01hdHJpeCBpbnN0ZWFkIG9mIFRpbGVNYXRyaXgKCjxkZXRhaWxzPgo8c3VtbWFyeT5BcmNoUiBnZW5lIGFjdGl2aXR5IHNjb3JlcyBjb21wdXRlZCB1c2luZyBUU1MsIG5vIGdlbmUgYm9keSBhbmQgUGVha01hdHJpeCBpbnN0ZWFkIG9mIFRpbGVNYXRyaXg8L3N1bW1hcnk+CgpgYGAje3J9CnByb2ogPC0gbG9hZEFyY2hSUHJvamVjdCgiMTJfYWN0aXZpdHlfc2NvcmVzX1RTU19wZWFrcy8iKQoKcHJvaiA8LSBhZGRLYXRoaUdlbmVTY29yZU1hdHJpeCgKICBwcm9qLAogIGdlbmVzID0gZ2V0R2VuZXMocHJvaiksCiAgcGVha3MgPSBnZXRQZWFrU2V0KHByb2opLAogIGdlbmVNb2RlbCA9ICJleHAoLWFicyh4KS81MDAwKSIsCiAgbWF0cml4TmFtZSA9ICJHZW5lU2NvcmVNYXRyaXgiLAogIGV4dGVuZFVwc3RyZWFtID0gYygxMDAwLCAxMDAwMDApLAogIGV4dGVuZERvd25zdHJlYW0gPSBjKDEwMDAsIDEwMDAwMCksCiAgI2dlbmVVcHN0cmVhbSA9IDUwMDAsICNOZXcgUGFyYW0KICAjZ2VuZURvd25zdHJlYW0gPSAwLCAjTmV3IFBhcmFtCiAgdXNlR2VuZUJvdW5kYXJpZXMgPSBUUlVFLAogIHVzZVRTUyA9IFRSVUUsICNOZXcgUGFyYW0KICBleHRlbmRUU1MgPSBGQUxTRSwKICB0aWxlU2l6ZSA9IDUwMCwKICBjZWlsaW5nID0gNCwKICBnZW5lU2NhbGVGYWN0b3IgPSA1LCAjTmV3IFBhcmFtCiAgc2NhbGVUbyA9IDEwMDAwLAogIGV4Y2x1ZGVDaHIgPSBjKCJjaHJZIiwgImNock0iKSwKICBibGFja2xpc3QgPSBnZXRCbGFja2xpc3QocHJvaiksCiAgdGhyZWFkcyA9IDEsCiAgcGFyYWxsZWxQYXJhbSA9IE5VTEwsCiAgc3ViVGhyZWFkaW5nID0gVFJVRSwKICBmb3JjZSA9IFRSVUUsCiAgbG9nRmlsZSA9IGNyZWF0ZUxvZ0ZpbGUoIi5hZGRLYXRoaUdlbmVTY29yZU1hdCIpKQoKc2NvcmVzIDwtIGdldE1hdHJpeEZyb21Qcm9qZWN0KHByb2osIHVzZU1hdHJpeCA9ICJHZW5lU2NvcmVNYXRyaXgiKQoKc2NvcmVzX21hdCA8LSBhc3NheXMoc2NvcmVzKVtbMV1dCnJvd25hbWVzKHNjb3Jlc19tYXQpIDwtIHJvd0RhdGEoc2NvcmVzKSRuYW1lCgojCiMgc2NlIDwtIFNpbmdsZUNlbGxFeHBlcmltZW50KGxpc3Qoc2NvcmVzPXNjb3Jlc19tYXQpLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgcm93RGF0YSA9IGFzLmRhdGEuZnJhbWUocm93bmFtZXMoc2NvcmVzX21hdCkpLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sRGF0YSA9IGFzLmRhdGEuZnJhbWUoY29sbmFtZXMoc2NvcmVzX21hdCkpKQojIAojIHdyaXRlSDVBRChzY2UsICIvb21pY3MvZ3JvdXBzL09FMDUzMy9pbnRlcm5hbC9rYXRoYXJpbmEvc2NEb1JJL2dhc3RydWxhdGlvbl9kYXRhL2p1cHl0ZXJfbm90ZWJvb2tzL3AyZ19nZW5lX2FjdGl2aXR5X3Njb3Jlcy9hcmNocl9zY29yZXNfcGVha19iYXNlZCIsIFhfbmFtZSA9ICJzY29yZXMiKQpgYGAKCmBgYCN7cn0KCgoKIyBzY2UgPC0gU2luZ2xlQ2VsbEV4cGVyaW1lbnQobGlzdChwMmdfbWF0ID0gcDJnX21hdCkpCiMgCiMgd3JpdGVINUFEKHNjZSwgIi9vbWljcy9ncm91cHMvT0UwNTMzL2ludGVybmFsL2thdGhhcmluYS9zY0RvUkkvZ2FzdHJ1bGF0aW9uX2RhdGEvanVweXRlcl9ub3RlYm9va3MvcDJnX2dlbmVfYWN0aXZpdHlfc2NvcmVzL3AyZ19tYXRfMjUwa2IiLAojICAgICAgICAgICBYX25hbWUgPSAicDJnX21hdCIpCgojIAojIAojIHNjZSA8LSBTaW5nbGVDZWxsRXhwZXJpbWVudChsaXN0KHBlYWtfbWF0ID0gcGVha19tYXQpKQojIAojIHdyaXRlSDVBRChzY2UsICIvb21pY3MvZ3JvdXBzL09FMDUzMy9pbnRlcm5hbC9rYXRoYXJpbmEvc2NEb1JJL2dhc3RydWxhdGlvbl9kYXRhL2p1cHl0ZXJfbm90ZWJvb2tzL3AyZ19nZW5lX2FjdGl2aXR5X3Njb3Jlcy9wZWFrX21hdCIsCiMgICAgICAgICAgIFhfbmFtZSA9ICJwZWFrX21hdCIpCgoKIyBjcF9uYW1lcyA8LSBjb2xuYW1lcyhjb2xEYXRhKGdlbmVfZXhwcikpCiMgY3BfbmFtZXNbMjBdIDwtICJjZWxsdHlwZXMiCiMgY29sbmFtZXMoY29sRGF0YShnZW5lX2V4cHIpKSA8LSBjcF9uYW1lcwoKc2NlIDwtIFNpbmdsZUNlbGxFeHBlcmltZW50KGxpc3QoZ2VuZXMgPSBleHByX21hdCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICNyb3dEYXRhID0gYXMuZGF0YS5mcmFtZShyb3duYW1lcyhnZW5lX2V4cHIpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sRGF0YSA9IGFzLmRhdGEuZnJhbWUoY29sRGF0YShnZW5lX2V4cHIpKSkKCiMgd3JpdGVINUFEKHNjZSwgIi9vbWljcy9ncm91cHMvT0UwNTMzL2ludGVybmFsL2thdGhhcmluYS9zY0RvUkkvZ2FzdHJ1bGF0aW9uX2RhdGEvanVweXRlcl9ub3RlYm9va3MvcDJnX2dlbmVfYWN0aXZpdHlfc2NvcmVzL2dlbmVfZXhwcl9tYXQiLAojICAgICAgICAgICBYX25hbWUgPSAiZ2VuZXMiKQojIAojIAojICNwMmdfbWF0X25vcm0gPC0gcDJnX21hdCAvIHJvd1N1bXMocDJnX21hdCkKIyBzY29yZXMgPC0gcDJnX21hdCAlKiUgcGVha19tYXQKIyBzY29yZXMgPC0gdCh0KHNjb3JlcykgLyBjb2xTdW1zKHNjb3JlcykpCiMgc3RvcGlmbm90KGFueShpcy5uYShzY29yZXMpKSA9PSBGQUxTRSkKIyBzY29yZXNAeCA8LSBwbWluKDFlOSwgZXhwKHNjb3Jlc0B4KSAtIDEpCiMgCiMgCiMgCiMgc2NlIDwtIFNpbmdsZUNlbGxFeHBlcmltZW50KGxpc3QoaW52ZXN0aWdhdGlvbiA9IGludmVzdGlnYXRpb24pKQojIAojIHdyaXRlSDVBRChzY2UsICIvb21pY3MvZ3JvdXBzL09FMDUzMy9pbnRlcm5hbC9rYXRoYXJpbmEvc2NEb1JJL2dhc3RydWxhdGlvbl9kYXRhL2p1cHl0ZXJfbm90ZWJvb2tzL3AyZ19nZW5lX2FjdGl2aXR5X3Njb3Jlcy9pbnZlc3RpZ2F0aW9uX3Njb3JlcyIsCiMgICAgICAgICAgIFhfbmFtZSA9ICJpbnZlc3RpZ2F0aW9uIikKCgoKCgojIGxhdGVudCBlbWJlZGRpbmcKZW1iIDwtIGdldFJlZHVjZWREaW1zKAogIEFyY2hSUHJvaiA9IHByb2osCiAgcmVkdWNlZERpbXMgPSAiYXRhY19MU0lfMTAwMDAwIiwKICByZXR1cm5NYXRyaXggPSBUUlVFLAogIGRpbXNUb1VzZSA9IDE6MzAsCiAgc2NhbGVEaW1zID0gTlVMTCwKICBjb3JDdXRPZmYgPSAwLjc1CikKZGltKGVtYikKCgpzY2UgPC0gU2luZ2xlQ2VsbEV4cGVyaW1lbnQobGlzdChlbWJlZGRpbmcgPSBlbWIpKQoKd3JpdGVINUFEKHNjZSwgIi9vbWljcy9ncm91cHMvT0UwNTMzL2ludGVybmFsL2thdGhhcmluYS9zY0RvUkkvZ2FzdHJ1bGF0aW9uX2RhdGEvanVweXRlcl9ub3RlYm9va3MvcDJnX2dlbmVfYWN0aXZpdHlfc2NvcmVzL2FyY2hyX2xzaV9lbWJlZGRpbmciLAogICAgICAgICAgWF9uYW1lID0gImVtYmVkZGluZyIpCgoKYGBg